1 /*
   2  * CDDL HEADER START
   3  *
   4  * The contents of this file are subject to the terms of the
   5  * Common Development and Distribution License (the "License").
   6  * You may not use this file except in compliance with the License.
   7  *
   8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
   9  * or http://www.opensolaris.org/os/licensing.
  10  * See the License for the specific language governing permissions
  11  * and limitations under the License.
  12  *
  13  * When distributing Covered Code, include this CDDL HEADER in each
  14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
  15  * If applicable, add the following below this CDDL HEADER, with the
  16  * fields enclosed by brackets "[]" replaced with your own identifying
  17  * information: Portions Copyright [yyyy] [name of copyright owner]
  18  *
  19  * CDDL HEADER END
  20  */
  21 /*
  22  * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
  23  * Use is subject to license terms.
  24  */
  25 
  26 /*
  27  * t1394.c
  28  *    1394 Target Driver Interface
  29  *    This file contains all of the 1394 Software Framework routines called
  30  *    by target drivers
  31  */
  32 
  33 #include <sys/sysmacros.h>
  34 #include <sys/conf.h>
  35 #include <sys/ddi.h>
  36 #include <sys/sunddi.h>
  37 #include <sys/types.h>
  38 #include <sys/kmem.h>
  39 #include <sys/disp.h>
  40 #include <sys/tnf_probe.h>
  41 
  42 #include <sys/1394/t1394.h>
  43 #include <sys/1394/s1394.h>
  44 #include <sys/1394/h1394.h>
  45 #include <sys/1394/ieee1394.h>
  46 
  47 static int s1394_allow_detach = 0;
  48 
  49 /*
  50  * Function:    t1394_attach()
  51  * Input(s):    dip                     The dip given to the target driver
  52  *                                          in it's attach() routine
  53  *              version                 The version of the target driver -
  54  *                                          T1394_VERSION_V1
  55  *              flags                   The flags parameter is unused (for now)
  56  *
  57  * Output(s):   attachinfo              Used to pass info back to target,
  58  *                                          including bus generation, local
  59  *                                          node ID, dma attribute, etc.
  60  *              t1394_hdl               The target "handle" to be used for
  61  *                                          all subsequent calls into the
  62  *                                          1394 Software Framework
  63  *
  64  * Description: t1394_attach() registers the target (based on its dip) with
  65  *              the 1394 Software Framework.  It returns the bus_generation,
  66  *              local_nodeID, iblock_cookie and other useful information to
  67  *              the target, as well as a handle (t1394_hdl) that will be used
  68  *              in all subsequent calls into this framework.
  69  */
  70 /* ARGSUSED */
  71 int
  72 t1394_attach(dev_info_t *dip, int version, uint_t flags,
  73     t1394_attachinfo_t *attachinfo, t1394_handle_t *t1394_hdl)
  74 {
  75         s1394_hal_t     *hal;
  76         s1394_target_t  *target;
  77         uint_t          dev;
  78         uint_t          curr;
  79         uint_t          unit_dir;
  80         int             hp_node = 0;
  81 
  82         ASSERT(t1394_hdl != NULL);
  83         ASSERT(attachinfo != NULL);
  84 
  85         TNF_PROBE_0_DEBUG(t1394_attach_enter, S1394_TNF_SL_HOTPLUG_STACK, "");
  86 
  87         *t1394_hdl = NULL;
  88 
  89         if (version != T1394_VERSION_V1) {
  90                 TNF_PROBE_1(t1394_attach_error, S1394_TNF_SL_HOTPLUG_ERROR, "",
  91                     tnf_string, msg, "Invalid version");
  92                 TNF_PROBE_0_DEBUG(t1394_attach_exit,
  93                     S1394_TNF_SL_HOTPLUG_STACK, "");
  94                 return (DDI_FAILURE);
  95         }
  96 
  97         hal = s1394_dip_to_hal(ddi_get_parent(dip));
  98         if (hal == NULL) {
  99                 TNF_PROBE_1(t1394_attach_error, S1394_TNF_SL_HOTPLUG_ERROR, "",
 100                     tnf_string, msg, "No parent dip found for target");
 101                 TNF_PROBE_0_DEBUG(t1394_attach_exit,
 102                     S1394_TNF_SL_HOTPLUG_STACK, "");
 103                 return (DDI_FAILURE);
 104         }
 105 
 106         ASSERT(MUTEX_NOT_HELD(&hal->topology_tree_mutex));
 107 
 108         hp_node = ddi_prop_exists(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS,
 109             "hp-node");
 110 
 111         /* Allocate space for s1394_target_t */
 112         target = kmem_zalloc(sizeof (s1394_target_t), KM_SLEEP);
 113 
 114         mutex_enter(&hal->topology_tree_mutex);
 115 
 116         target->target_version = version;
 117 
 118         /* Copy in the params */
 119         target->target_dip = dip;
 120         target->on_hal          = hal;
 121 
 122         /* Place the target on the appropriate node */
 123         target->on_node      = NULL;
 124 
 125         rw_enter(&target->on_hal->target_list_rwlock, RW_WRITER);
 126         if (hp_node != 0) {
 127                 s1394_add_target_to_node(target);
 128                 /*
 129                  * on_node can be NULL if the node got unplugged
 130                  * while the target driver is in its attach routine.
 131                  */
 132                 if (target->on_node == NULL) {
 133                         s1394_remove_target_from_node(target);
 134                         rw_exit(&target->on_hal->target_list_rwlock);
 135                         mutex_exit(&hal->topology_tree_mutex);
 136                         kmem_free(target, sizeof (s1394_target_t));
 137                         TNF_PROBE_1(t1394_attach_error,
 138                             S1394_TNF_SL_HOTPLUG_ERROR, "", tnf_string, msg,
 139                             "on_node == NULL");
 140                         TNF_PROBE_0_DEBUG(t1394_attach_exit,
 141                             S1394_TNF_SL_HOTPLUG_STACK, "");
 142                         return (DDI_FAILURE);
 143                 }
 144 
 145                 target->target_state = S1394_TARG_HP_NODE;
 146                 if (S1394_NODE_BUS_PWR_CONSUMER(target->on_node) == B_TRUE)
 147                         target->target_state |= S1394_TARG_BUS_PWR_CONSUMER;
 148         }
 149 
 150         /* Return the current generation */
 151         attachinfo->localinfo.bus_generation = target->on_hal->generation_count;
 152 
 153         /* Fill in hal node id */
 154         attachinfo->localinfo.local_nodeID = target->on_hal->node_id;
 155 
 156         /* Give the target driver the iblock_cookie */
 157         attachinfo->iblock_cookie = target->on_hal->halinfo.hw_interrupt;
 158 
 159         /* Give the target driver the attributes */
 160         attachinfo->acc_attr = target->on_hal->halinfo.acc_attr;
 161         attachinfo->dma_attr = target->on_hal->halinfo.dma_attr;
 162 
 163         unit_dir = ddi_prop_get_int(DDI_DEV_T_ANY, dip,
 164                 DDI_PROP_DONTPASS, "unit-dir-offset", 0);
 165         target->unit_dir = unit_dir;
 166 
 167         /* By default, disable all physical AR requests */
 168         target->physical_arreq_enabled = 0;
 169 
 170 
 171         /* Get dev_max_payload & current_max_payload */
 172         s1394_get_maxpayload(target, &dev, &curr);
 173         target->dev_max_payload              = dev;
 174         target->current_max_payload  = curr;
 175 
 176         /* Add into linked list */
 177         if ((target->on_hal->target_head == NULL) &&
 178             (target->on_hal->target_tail == NULL)) {
 179                 target->on_hal->target_head = target;
 180                 target->on_hal->target_tail = target;
 181         } else {
 182                 target->on_hal->target_tail->target_next = target;
 183                 target->target_prev = target->on_hal->target_tail;
 184                 target->on_hal->target_tail = target;
 185         }
 186         rw_exit(&target->on_hal->target_list_rwlock);
 187 
 188         /* Fill in services layer private info */
 189         *t1394_hdl = (t1394_handle_t)target;
 190 
 191         mutex_exit(&hal->topology_tree_mutex);
 192 
 193         TNF_PROBE_0_DEBUG(t1394_attach_exit, S1394_TNF_SL_HOTPLUG_STACK, "");
 194         return (DDI_SUCCESS);
 195 }
 196 
 197 /*
 198  * Function:    t1394_detach()
 199  * Input(s):    t1394_hdl               The target "handle" returned by
 200  *                                          t1394_attach()
 201  *              flags                   The flags parameter is unused (for now)
 202  *
 203  * Output(s):   DDI_SUCCESS             Target successfully detached
 204  *              DDI_FAILURE             Target failed to detach
 205  *
 206  * Description: t1394_detach() unregisters the target from the 1394 Software
 207  *              Framework.  t1394_detach() can fail if the target has any
 208  *              allocated commands that haven't been freed.
 209  */
 210 /* ARGSUSED */
 211 int
 212 t1394_detach(t1394_handle_t *t1394_hdl, uint_t flags)
 213 {
 214         s1394_target_t  *target;
 215         uint_t          num_cmds;
 216 
 217         TNF_PROBE_0_DEBUG(t1394_detach_enter, S1394_TNF_SL_HOTPLUG_STACK, "");
 218 
 219         ASSERT(t1394_hdl != NULL);
 220 
 221         target = (s1394_target_t *)(*t1394_hdl);
 222 
 223         ASSERT(target->on_hal);
 224 
 225         mutex_enter(&target->on_hal->topology_tree_mutex);
 226         rw_enter(&target->on_hal->target_list_rwlock, RW_WRITER);
 227 
 228         /* How many cmds has this target allocated? */
 229         num_cmds = target->target_num_cmds;
 230 
 231         if (num_cmds != 0) {
 232                 rw_exit(&target->on_hal->target_list_rwlock);
 233                 mutex_exit(&target->on_hal->topology_tree_mutex);
 234                 TNF_PROBE_1(t1394_detach_error, S1394_TNF_SL_HOTPLUG_ERROR, "",
 235                     tnf_string, msg, "Must free all commands before detach()");
 236                 TNF_PROBE_0_DEBUG(t1394_detach_exit,
 237                     S1394_TNF_SL_HOTPLUG_STACK, "");
 238                 return (DDI_FAILURE);
 239         }
 240 
 241         /*
 242          * Remove from linked lists. Topology tree is already locked
 243          * so that the node won't go away while we are looking at it.
 244          */
 245         if ((target->on_hal->target_head == target) &&
 246             (target->on_hal->target_tail == target)) {
 247                 target->on_hal->target_head = NULL;
 248                 target->on_hal->target_tail = NULL;
 249         } else {
 250                 if (target->target_prev)
 251                         target->target_prev->target_next = target->target_next;
 252                 if (target->target_next)
 253                         target->target_next->target_prev = target->target_prev;
 254                 if (target->on_hal->target_head == target)
 255                         target->on_hal->target_head = target->target_next;
 256                 if (target->on_hal->target_tail == target)
 257                         target->on_hal->target_tail = target->target_prev;
 258         }
 259 
 260         s1394_remove_target_from_node(target);
 261         rw_exit(&target->on_hal->target_list_rwlock);
 262 
 263         mutex_exit(&target->on_hal->topology_tree_mutex);
 264 
 265         /* Free memory */
 266         kmem_free(target, sizeof (s1394_target_t));
 267 
 268         *t1394_hdl = NULL;
 269 
 270         TNF_PROBE_0_DEBUG(t1394_detach_exit, S1394_TNF_SL_HOTPLUG_STACK, "");
 271         return (DDI_SUCCESS);
 272 }
 273 
 274 /*
 275  * Function:    t1394_alloc_cmd()
 276  * Input(s):    t1394_hdl               The target "handle" returned by
 277  *                                          t1394_attach()
 278  *              flags                   The flags parameter is described below
 279  *
 280  * Output(s):   cmdp                    Pointer to the newly allocated command
 281  *
 282  * Description: t1394_alloc_cmd() allocates a command for use with the
 283  *              t1394_read(), t1394_write(), or t1394_lock() interfaces
 284  *              of the 1394 Software Framework.  By default, t1394_alloc_cmd()
 285  *              may sleep while allocating memory for the command structure.
 286  *              If this is undesirable, the target may set the
 287  *              T1394_ALLOC_CMD_NOSLEEP bit in the flags parameter.  Also,
 288  *              this call may fail because a target driver has already
 289  *              allocated MAX_NUMBER_ALLOC_CMDS commands.
 290  */
 291 int
 292 t1394_alloc_cmd(t1394_handle_t t1394_hdl, uint_t flags, cmd1394_cmd_t **cmdp)
 293 {
 294         s1394_hal_t      *hal;
 295         s1394_target_t   *target;
 296         s1394_cmd_priv_t *s_priv;
 297         uint_t           num_cmds;
 298 
 299         TNF_PROBE_0_DEBUG(t1394_alloc_cmd_enter, S1394_TNF_SL_ATREQ_STACK, "");
 300 
 301         ASSERT(t1394_hdl != NULL);
 302 
 303         target = (s1394_target_t *)t1394_hdl;
 304 
 305         /* Find the HAL this target resides on */
 306         hal = target->on_hal;
 307 
 308         rw_enter(&hal->target_list_rwlock, RW_WRITER);
 309 
 310         /* How many cmds has this target allocated? */
 311         num_cmds = target->target_num_cmds;
 312 
 313         if (num_cmds >= MAX_NUMBER_ALLOC_CMDS) {
 314                 rw_exit(&hal->target_list_rwlock);
 315                 TNF_PROBE_1(t1394_alloc_cmd_error, S1394_TNF_SL_ATREQ_ERROR,
 316                     "", tnf_string, msg, "Attempted to alloc > "
 317                     "MAX_NUMBER_ALLOC_CMDS");
 318                 TNF_PROBE_0_DEBUG(t1394_alloc_cmd_exit,
 319                     S1394_TNF_SL_ATREQ_STACK, "");
 320                 /* kstats - cmd alloc failures */
 321                 hal->hal_kstats->cmd_alloc_fail++;
 322                 return (DDI_FAILURE);
 323         }
 324 
 325         /* Increment the number of cmds this target has allocated? */
 326         target->target_num_cmds = num_cmds + 1;
 327 
 328         if (s1394_alloc_cmd(hal, flags, cmdp) != DDI_SUCCESS) {
 329                 target->target_num_cmds = num_cmds;  /* Undo increment */
 330                 rw_exit(&hal->target_list_rwlock);
 331                 TNF_PROBE_1(t1394_alloc_cmd_error, S1394_TNF_SL_ATREQ_ERROR, "",
 332                     tnf_string, msg, "Failed to allocate command structure");
 333                 TNF_PROBE_0_DEBUG(t1394_alloc_cmd_exit,
 334                     S1394_TNF_SL_ATREQ_STACK, "");
 335                 /* kstats - cmd alloc failures */
 336                 hal->hal_kstats->cmd_alloc_fail++;
 337                 return (DDI_FAILURE);
 338         }
 339 
 340         rw_exit(&hal->target_list_rwlock);
 341 
 342         /* Get the Services Layer private area */
 343         s_priv = S1394_GET_CMD_PRIV(*cmdp);
 344 
 345         /* Initialize the command's blocking mutex */
 346         mutex_init(&s_priv->blocking_mutex, NULL, MUTEX_DRIVER,
 347             hal->halinfo.hw_interrupt);
 348 
 349         /* Initialize the command's blocking condition variable */
 350         cv_init(&s_priv->blocking_cv, NULL, CV_DRIVER, NULL);
 351 
 352         TNF_PROBE_0_DEBUG(t1394_alloc_cmd_exit, S1394_TNF_SL_ATREQ_STACK, "");
 353         return (DDI_SUCCESS);
 354 }
 355 
 356 /*
 357  * Function:    t1394_free_cmd()
 358  * Input(s):    t1394_hdl               The target "handle" returned by
 359  *                                          t1394_attach()
 360  *              flags                   The flags parameter is unused (for now)
 361  *              cmdp                    Pointer to the command to be freed
 362  *
 363  * Output(s):   DDI_SUCCESS             Target successfully freed command
 364  *              DDI_FAILURE             Target failed to free command
 365  *
 366  * Description: t1394_free_cmd() attempts to free a command that has previously
 367  *              been allocated by the target driver.  It is possible for
 368  *              t1394_free_cmd() to fail because the command is currently
 369  *              in-use by the 1394 Software Framework.
 370  */
 371 /* ARGSUSED */
 372 int
 373 t1394_free_cmd(t1394_handle_t t1394_hdl, uint_t flags, cmd1394_cmd_t **cmdp)
 374 {
 375         s1394_hal_t      *hal;
 376         s1394_target_t   *target;
 377         s1394_cmd_priv_t *s_priv;
 378         uint_t           num_cmds;
 379 
 380         TNF_PROBE_0_DEBUG(t1394_free_cmd_enter, S1394_TNF_SL_ATREQ_STACK, "");
 381 
 382         ASSERT(t1394_hdl != NULL);
 383 
 384         target = (s1394_target_t *)t1394_hdl;
 385 
 386         /* Find the HAL this target resides on */
 387         hal = target->on_hal;
 388 
 389         rw_enter(&hal->target_list_rwlock, RW_WRITER);
 390 
 391         /* How many cmds has this target allocated? */
 392         num_cmds = target->target_num_cmds;
 393 
 394         if (num_cmds == 0) {
 395                 rw_exit(&hal->target_list_rwlock);
 396                 TNF_PROBE_2(t1394_free_cmd_error, S1394_TNF_SL_ATREQ_ERROR, "",
 397                     tnf_string, msg, "No commands left to be freed "
 398                     "(num_cmds <= 0)", tnf_uint, num_cmds, num_cmds);
 399                 TNF_PROBE_0_DEBUG(t1394_free_cmd_exit,
 400                     S1394_TNF_SL_ATREQ_STACK, "");
 401                 ASSERT(num_cmds != 0);
 402                 return (DDI_FAILURE);
 403         }
 404 
 405         /* Get the Services Layer private area */
 406         s_priv = S1394_GET_CMD_PRIV(*cmdp);
 407 
 408         /* Check that command isn't in use */
 409         if (s_priv->cmd_in_use == B_TRUE) {
 410                 rw_exit(&hal->target_list_rwlock);
 411                 TNF_PROBE_1(t1394_free_cmd_error, S1394_TNF_SL_ATREQ_ERROR, "",
 412                     tnf_string, msg, "Attempted to free an in-use command");
 413                 TNF_PROBE_0_DEBUG(t1394_free_cmd_exit,
 414                     S1394_TNF_SL_ATREQ_STACK, "");
 415                 ASSERT(s_priv->cmd_in_use == B_FALSE);
 416                 return (DDI_FAILURE);
 417         }
 418 
 419         /* Decrement the number of cmds this target has allocated */
 420         target->target_num_cmds--;
 421 
 422         rw_exit(&hal->target_list_rwlock);
 423 
 424         /* Destroy the command's blocking condition variable */
 425         cv_destroy(&s_priv->blocking_cv);
 426 
 427         /* Destroy the command's blocking mutex */
 428         mutex_destroy(&s_priv->blocking_mutex);
 429 
 430         kmem_cache_free(hal->hal_kmem_cachep, *cmdp);
 431 
 432         /* Command pointer is set to NULL before returning */
 433         *cmdp = NULL;
 434 
 435         /* kstats - number of cmd frees */
 436         hal->hal_kstats->cmd_free++;
 437 
 438         TNF_PROBE_0_DEBUG(t1394_free_cmd_exit, S1394_TNF_SL_ATREQ_STACK, "");
 439         return (DDI_SUCCESS);
 440 }
 441 
 442 /*
 443  * Function:    t1394_read()
 444  * Input(s):    t1394_hdl               The target "handle" returned by
 445  *                                          t1394_attach()
 446  *              cmd                     Pointer to the command to send
 447  *
 448  * Output(s):   DDI_SUCCESS             Target successful sent the command
 449  *              DDI_FAILURE             Target failed to send command
 450  *
 451  * Description: t1394_read() attempts to send an asynchronous read request
 452  *              onto the 1394 bus.
 453  */
 454 int
 455 t1394_read(t1394_handle_t t1394_hdl, cmd1394_cmd_t *cmd)
 456 {
 457         s1394_hal_t       *to_hal;
 458         s1394_target_t    *target;
 459         s1394_cmd_priv_t  *s_priv;
 460         s1394_hal_state_t state;
 461         int               ret;
 462         int               err;
 463 
 464         TNF_PROBE_0_DEBUG(t1394_read_enter, S1394_TNF_SL_ATREQ_STACK, "");
 465 
 466         ASSERT(t1394_hdl != NULL);
 467         ASSERT(cmd != NULL);
 468 
 469         /* Get the Services Layer private area */
 470         s_priv = S1394_GET_CMD_PRIV(cmd);
 471 
 472         /* Is this command currently in use? */
 473         if (s_priv->cmd_in_use == B_TRUE) {
 474                 TNF_PROBE_1(t1394_read_error, S1394_TNF_SL_ATREQ_ERROR, "",
 475                     tnf_string, msg, "Attempted to resend an in-use command");
 476                 TNF_PROBE_0_DEBUG(t1394_read_exit, S1394_TNF_SL_ATREQ_STACK,
 477                     "");
 478                 ASSERT(s_priv->cmd_in_use == B_FALSE);
 479                 return (DDI_FAILURE);
 480         }
 481 
 482         target = (s1394_target_t *)t1394_hdl;
 483 
 484         /* Set-up the destination of the command */
 485         to_hal = target->on_hal;
 486 
 487         /* No status (default) */
 488         cmd->cmd_result = CMD1394_NOSTATUS;
 489 
 490         /* Check for proper command type */
 491         if ((cmd->cmd_type != CMD1394_ASYNCH_RD_QUAD) &&
 492             (cmd->cmd_type != CMD1394_ASYNCH_RD_BLOCK)) {
 493                 cmd->cmd_result = CMD1394_EINVALID_COMMAND;
 494                 TNF_PROBE_1(t1394_read_error, S1394_TNF_SL_ATREQ_ERROR, "",
 495                     tnf_string, msg, "Invalid command type specified");
 496                 TNF_PROBE_0_DEBUG(t1394_read_exit,
 497                     S1394_TNF_SL_ATREQ_STACK, "");
 498                 return (DDI_FAILURE);
 499         }
 500 
 501         /* Is this a blocking command on interrupt stack? */
 502         if ((cmd->cmd_options & CMD1394_BLOCKING) &&
 503             (servicing_interrupt())) {
 504                 cmd->cmd_result = CMD1394_EINVALID_CONTEXT;
 505                 TNF_PROBE_1(t1394_read_error, S1394_TNF_SL_ATREQ_ERROR, "",
 506                     tnf_string, msg, "Tried to use CMD1394_BLOCKING in "
 507                     "intr context");
 508                 TNF_PROBE_0_DEBUG(t1394_read_exit,
 509                     S1394_TNF_SL_ATREQ_STACK, "");
 510                 return (DDI_FAILURE);
 511         }
 512 
 513         mutex_enter(&to_hal->topology_tree_mutex);
 514         state = to_hal->hal_state;
 515         if (state != S1394_HAL_NORMAL) {
 516                 ret = s1394_HAL_asynch_error(to_hal, cmd, state);
 517                 if (ret != CMD1394_CMDSUCCESS) {
 518                         cmd->cmd_result = ret;
 519                         mutex_exit(&to_hal->topology_tree_mutex);
 520                         return (DDI_FAILURE);
 521                 }
 522         }
 523 
 524         ret = s1394_setup_asynch_command(to_hal, target, cmd,
 525             S1394_CMD_READ, &err);
 526 
 527         /* Command has now been put onto the queue! */
 528         if (ret != DDI_SUCCESS) {
 529                 /* Copy error code into result */
 530                 cmd->cmd_result = err;
 531                 mutex_exit(&to_hal->topology_tree_mutex);
 532                 TNF_PROBE_1(t1394_read_error, S1394_TNF_SL_ATREQ_ERROR, "",
 533                     tnf_string, msg, "Failed in s1394_setup_asynch_command()");
 534                 TNF_PROBE_0_DEBUG(t1394_read_exit,
 535                     S1394_TNF_SL_ATREQ_STACK, "");
 536                 return (DDI_FAILURE);
 537         }
 538 
 539         /*
 540          * If this command was sent during a bus reset,
 541          * then put it onto the pending Q.
 542          */
 543         if (state == S1394_HAL_RESET) {
 544                 /* Remove cmd from outstanding request Q */
 545                 s1394_remove_q_asynch_cmd(to_hal, cmd);
 546                 /* Are we on the bus reset event stack? */
 547                 if (s1394_on_br_thread(to_hal) == B_TRUE) {
 548                         /* Blocking commands are not allowed */
 549                         if (cmd->cmd_options & CMD1394_BLOCKING) {
 550                                 mutex_exit(&to_hal->topology_tree_mutex);
 551                                 s_priv->cmd_in_use = B_FALSE;
 552                                 cmd->cmd_result         = CMD1394_EINVALID_CONTEXT;
 553                                 TNF_PROBE_1(t1394_read_error,
 554                                     S1394_TNF_SL_ATREQ_ERROR, "", tnf_string,
 555                                     msg, "CMD1394_BLOCKING in bus reset "
 556                                     "context");
 557                                 TNF_PROBE_0_DEBUG(t1394_read_exit,
 558                                     S1394_TNF_SL_ATREQ_STACK, "");
 559                                 return (DDI_FAILURE);
 560                         }
 561                 }
 562 
 563                 s1394_pending_q_insert(to_hal, cmd, S1394_PENDING_Q_FRONT);
 564                 mutex_exit(&to_hal->topology_tree_mutex);
 565 
 566                 /* Block (if necessary) */
 567                 goto block_on_asynch_cmd;
 568         }
 569         mutex_exit(&to_hal->topology_tree_mutex);
 570 
 571         /* Send the command out */
 572         ret = s1394_xfer_asynch_command(to_hal, cmd, &err);
 573 
 574         if (ret != DDI_SUCCESS) {
 575                 if (err == CMD1394_ESTALE_GENERATION) {
 576                         /* Remove cmd from outstanding request Q */
 577                         s1394_remove_q_asynch_cmd(to_hal, cmd);
 578                         s1394_pending_q_insert(to_hal, cmd,
 579                             S1394_PENDING_Q_FRONT);
 580 
 581                         /* Block (if necessary) */
 582                         goto block_on_asynch_cmd;
 583 
 584                 } else {
 585                         /* Remove cmd from outstanding request Q */
 586                         s1394_remove_q_asynch_cmd(to_hal, cmd);
 587 
 588                         s_priv->cmd_in_use = B_FALSE;
 589 
 590                         /* Copy error code into result */
 591                         cmd->cmd_result    = err;
 592 
 593                         TNF_PROBE_1(t1394_read_error, S1394_TNF_SL_ATREQ_ERROR,
 594                             "", tnf_string, msg, "Failed in "
 595                             "s1394_xfer_asynch_command()");
 596                         TNF_PROBE_0_DEBUG(t1394_read_exit,
 597                             S1394_TNF_SL_ATREQ_STACK, "");
 598                         return (DDI_FAILURE);
 599                 }
 600         } else {
 601                 /* Block (if necessary) */
 602                 goto block_on_asynch_cmd;
 603         }
 604 
 605 block_on_asynch_cmd:
 606         s1394_block_on_asynch_cmd(cmd);
 607 
 608         TNF_PROBE_0_DEBUG(t1394_read_exit,
 609             S1394_TNF_SL_ATREQ_STACK, "");
 610         return (DDI_SUCCESS);
 611 }
 612 
 613 /*
 614  * Function:    t1394_write()
 615  * Input(s):    t1394_hdl               The target "handle" returned by
 616  *                                          t1394_attach()
 617  *              cmd                     Pointer to the command to send
 618  *
 619  * Output(s):   DDI_SUCCESS             Target successful sent the command
 620  *              DDI_FAILURE             Target failed to send command
 621  *
 622  * Description: t1394_write() attempts to send an asynchronous write request
 623  *              onto the 1394 bus.
 624  */
 625 int
 626 t1394_write(t1394_handle_t t1394_hdl, cmd1394_cmd_t *cmd)
 627 {
 628         s1394_hal_t       *to_hal;
 629         s1394_target_t    *target;
 630         s1394_cmd_priv_t  *s_priv;
 631         s1394_hal_state_t state;
 632         int               ret;
 633         int               err;
 634 
 635         TNF_PROBE_0_DEBUG(t1394_write_enter, S1394_TNF_SL_ATREQ_STACK, "");
 636 
 637         ASSERT(t1394_hdl != NULL);
 638         ASSERT(cmd != NULL);
 639 
 640         /* Get the Services Layer private area */
 641         s_priv = S1394_GET_CMD_PRIV(cmd);
 642 
 643         /* Is this command currently in use? */
 644         if (s_priv->cmd_in_use == B_TRUE) {
 645                 TNF_PROBE_1(t1394_write_error, S1394_TNF_SL_ATREQ_ERROR, "",
 646                     tnf_string, msg, "Attempted to resend an in-use command");
 647                 TNF_PROBE_0_DEBUG(t1394_write_exit, S1394_TNF_SL_ATREQ_STACK,
 648                     "");
 649                 ASSERT(s_priv->cmd_in_use == B_FALSE);
 650                 return (DDI_FAILURE);
 651         }
 652 
 653         target = (s1394_target_t *)t1394_hdl;
 654 
 655         /* Set-up the destination of the command */
 656         to_hal = target->on_hal;
 657 
 658         /* Is this an FA request? */
 659         if (s_priv->cmd_ext_type == S1394_CMD_EXT_FA) {
 660                 if (S1394_IS_CMD_FCP(s_priv) &&
 661                     (s1394_fcp_write_check_cmd(cmd) != DDI_SUCCESS)) {
 662                         TNF_PROBE_0_DEBUG(t1394_write_exit,
 663                             S1394_TNF_SL_ATREQ_STACK, "");
 664                         return (DDI_FAILURE);
 665                 }
 666                 s1394_fa_convert_cmd(to_hal, cmd);
 667         }
 668 
 669         /* No status (default) */
 670         cmd->cmd_result = CMD1394_NOSTATUS;
 671 
 672         /* Check for proper command type */
 673         if ((cmd->cmd_type != CMD1394_ASYNCH_WR_QUAD) &&
 674             (cmd->cmd_type != CMD1394_ASYNCH_WR_BLOCK)) {
 675                 cmd->cmd_result = CMD1394_EINVALID_COMMAND;
 676                 s1394_fa_check_restore_cmd(to_hal, cmd);
 677                 TNF_PROBE_1(t1394_write_error, S1394_TNF_SL_ATREQ_ERROR, "",
 678                     tnf_string, msg, "Invalid command type specified");
 679                 TNF_PROBE_0_DEBUG(t1394_write_exit, S1394_TNF_SL_ATREQ_STACK,
 680                     "");
 681                 return (DDI_FAILURE);
 682         }
 683 
 684         /* Is this a blocking command on interrupt stack? */
 685         if ((cmd->cmd_options & CMD1394_BLOCKING) &&
 686             (servicing_interrupt())) {
 687                 cmd->cmd_result = CMD1394_EINVALID_CONTEXT;
 688                 s1394_fa_check_restore_cmd(to_hal, cmd);
 689                 TNF_PROBE_1(t1394_write_error, S1394_TNF_SL_ATREQ_ERROR, "",
 690                     tnf_string, msg, "Tried to use CMD1394_BLOCKING in intr "
 691                     "context");
 692                 TNF_PROBE_0_DEBUG(t1394_write_exit, S1394_TNF_SL_ATREQ_STACK,
 693                     "");
 694                 return (DDI_FAILURE);
 695         }
 696 
 697         mutex_enter(&to_hal->topology_tree_mutex);
 698         state = to_hal->hal_state;
 699         if (state != S1394_HAL_NORMAL) {
 700                 ret = s1394_HAL_asynch_error(to_hal, cmd, state);
 701                 if (ret != CMD1394_CMDSUCCESS) {
 702                         cmd->cmd_result = ret;
 703                         mutex_exit(&to_hal->topology_tree_mutex);
 704                         s1394_fa_check_restore_cmd(to_hal, cmd);
 705                         return (DDI_FAILURE);
 706                 }
 707         }
 708 
 709         ret = s1394_setup_asynch_command(to_hal, target, cmd,
 710             S1394_CMD_WRITE, &err);
 711 
 712         /* Command has now been put onto the queue! */
 713         if (ret != DDI_SUCCESS) {
 714                 /* Copy error code into result */
 715                 cmd->cmd_result = err;
 716                 mutex_exit(&to_hal->topology_tree_mutex);
 717                 s1394_fa_check_restore_cmd(to_hal, cmd);
 718                 TNF_PROBE_1(t1394_write_error, S1394_TNF_SL_ATREQ_ERROR, "",
 719                     tnf_string, msg, "Failed in s1394_setup_asynch_command()");
 720                 TNF_PROBE_0_DEBUG(t1394_write_exit, S1394_TNF_SL_ATREQ_STACK,
 721                     "");
 722                 return (DDI_FAILURE);
 723         }
 724 
 725         /*
 726          * If this command was sent during a bus reset,
 727          * then put it onto the pending Q.
 728          */
 729         if (state == S1394_HAL_RESET) {
 730                 /* Remove cmd from outstanding request Q */
 731                 s1394_remove_q_asynch_cmd(to_hal, cmd);
 732                 /* Are we on the bus reset event stack? */
 733                 if (s1394_on_br_thread(to_hal) == B_TRUE) {
 734                         /* Blocking commands are not allowed */
 735                         if (cmd->cmd_options & CMD1394_BLOCKING) {
 736                                 mutex_exit(&to_hal->topology_tree_mutex);
 737                                 s_priv->cmd_in_use = B_FALSE;
 738                                 cmd->cmd_result    = CMD1394_EINVALID_CONTEXT;
 739                                 s1394_fa_check_restore_cmd(to_hal, cmd);
 740                                 TNF_PROBE_1(t1394_write_error,
 741                                     S1394_TNF_SL_ATREQ_ERROR, "", tnf_string,
 742                                     msg, "CMD1394_BLOCKING in bus reset cntxt");
 743                                 TNF_PROBE_0_DEBUG(t1394_write_exit,
 744                                     S1394_TNF_SL_ATREQ_STACK, "");
 745                                 return (DDI_FAILURE);
 746                         }
 747                 }
 748 
 749                 s1394_pending_q_insert(to_hal, cmd, S1394_PENDING_Q_FRONT);
 750                 mutex_exit(&to_hal->topology_tree_mutex);
 751 
 752                 /* Block (if necessary) */
 753                 s1394_block_on_asynch_cmd(cmd);
 754 
 755                 TNF_PROBE_0_DEBUG(t1394_write_exit, S1394_TNF_SL_ATREQ_STACK,
 756                     "");
 757                 return (DDI_SUCCESS);
 758         }
 759         mutex_exit(&to_hal->topology_tree_mutex);
 760 
 761         /* Send the command out */
 762         ret = s1394_xfer_asynch_command(to_hal, cmd, &err);
 763 
 764         if (ret != DDI_SUCCESS) {
 765                 if (err == CMD1394_ESTALE_GENERATION) {
 766                         /* Remove cmd from outstanding request Q */
 767                         s1394_remove_q_asynch_cmd(to_hal, cmd);
 768                         s1394_pending_q_insert(to_hal, cmd,
 769                             S1394_PENDING_Q_FRONT);
 770 
 771                         /* Block (if necessary) */
 772                         s1394_block_on_asynch_cmd(cmd);
 773 
 774                         TNF_PROBE_0_DEBUG(t1394_write_exit,
 775                             S1394_TNF_SL_ATREQ_STACK, "");
 776                         return (DDI_SUCCESS);
 777                 } else {
 778                         /* Remove cmd from outstanding request Q */
 779                         s1394_remove_q_asynch_cmd(to_hal, cmd);
 780 
 781                         s_priv->cmd_in_use = B_FALSE;
 782 
 783                         /* Copy error code into result */
 784                         cmd->cmd_result = err;
 785 
 786                         s1394_fa_check_restore_cmd(to_hal, cmd);
 787                         TNF_PROBE_1(t1394_write_error,
 788                             S1394_TNF_SL_ATREQ_ERROR, "", tnf_string, msg,
 789                             "Failed in s1394_xfer_asynch_command()");
 790                         TNF_PROBE_0_DEBUG(t1394_write_exit,
 791                             S1394_TNF_SL_ATREQ_STACK, "");
 792                         return (DDI_FAILURE);
 793                 }
 794         } else {
 795                 /* Block (if necessary) */
 796                 s1394_block_on_asynch_cmd(cmd);
 797 
 798                 TNF_PROBE_0_DEBUG(t1394_write_exit, S1394_TNF_SL_ATREQ_STACK,
 799                     "");
 800                 return (DDI_SUCCESS);
 801         }
 802 }
 803 
 804 /*
 805  * Function:    t1394_lock()
 806  * Input(s):    t1394_hdl               The target "handle" returned by
 807  *                                          t1394_attach()
 808  *              cmd                     Pointer to the command to send
 809  *
 810  * Output(s):   DDI_SUCCESS             Target successful sent the command
 811  *              DDI_FAILURE             Target failed to send command
 812  *
 813  * Description: t1394_lock() attempts to send an asynchronous lock request
 814  *              onto the 1394 bus.
 815  */
 816 int
 817 t1394_lock(t1394_handle_t t1394_hdl, cmd1394_cmd_t *cmd)
 818 {
 819         s1394_hal_t         *to_hal;
 820         s1394_target_t      *target;
 821         s1394_cmd_priv_t    *s_priv;
 822         s1394_hal_state_t   state;
 823         cmd1394_lock_type_t lock_type;
 824         uint_t              num_retries;
 825         int                 ret;
 826 
 827         TNF_PROBE_0_DEBUG(t1394_lock_enter, S1394_TNF_SL_ATREQ_STACK, "");
 828 
 829         ASSERT(t1394_hdl != NULL);
 830         ASSERT(cmd != NULL);
 831 
 832         /* Get the Services Layer private area */
 833         s_priv = S1394_GET_CMD_PRIV(cmd);
 834 
 835         /* Is this command currently in use? */
 836         if (s_priv->cmd_in_use == B_TRUE) {
 837                 TNF_PROBE_1(t1394_lock_error, S1394_TNF_SL_ATREQ_ERROR, "",
 838                     tnf_string, msg, "Attempted to resend an in-use command");
 839                 TNF_PROBE_0_DEBUG(t1394_lock_exit, S1394_TNF_SL_ATREQ_STACK,
 840                     "");
 841                 ASSERT(s_priv->cmd_in_use == B_FALSE);
 842                 return (DDI_FAILURE);
 843         }
 844 
 845         target = (s1394_target_t *)t1394_hdl;
 846 
 847         /* Set-up the destination of the command */
 848         to_hal = target->on_hal;
 849 
 850         mutex_enter(&to_hal->topology_tree_mutex);
 851         state = to_hal->hal_state;
 852         if (state != S1394_HAL_NORMAL) {
 853                 ret = s1394_HAL_asynch_error(to_hal, cmd, state);
 854                 if (ret != CMD1394_CMDSUCCESS) {
 855                         cmd->cmd_result = ret;
 856                         mutex_exit(&to_hal->topology_tree_mutex);
 857                         return (DDI_FAILURE);
 858                 }
 859         }
 860         mutex_exit(&to_hal->topology_tree_mutex);
 861 
 862         /* Check for proper command type */
 863         if ((cmd->cmd_type != CMD1394_ASYNCH_LOCK_32) &&
 864             (cmd->cmd_type != CMD1394_ASYNCH_LOCK_64)) {
 865                 cmd->cmd_result = CMD1394_EINVALID_COMMAND;
 866                 TNF_PROBE_1(t1394_lock_error, S1394_TNF_SL_ATREQ_ERROR, "",
 867                     tnf_string, msg, "Invalid command type sent to "
 868                     "t1394_lock()");
 869                 TNF_PROBE_0_DEBUG(t1394_lock_exit, S1394_TNF_SL_ATREQ_STACK,
 870                     "");
 871                 return (DDI_FAILURE);
 872         }
 873 
 874         /* No status (default) */
 875         cmd->cmd_result = CMD1394_NOSTATUS;
 876 
 877         /* Is this a blocking command on interrupt stack? */
 878         if ((cmd->cmd_options & CMD1394_BLOCKING) &&
 879             (servicing_interrupt())) {
 880                 cmd->cmd_result = CMD1394_EINVALID_CONTEXT;
 881                 TNF_PROBE_1(t1394_lock_error, S1394_TNF_SL_ATREQ_ERROR, "",
 882                     tnf_string, msg, "Tried to use CMD1394_BLOCKING in intr "
 883                     "context");
 884                 TNF_PROBE_0_DEBUG(t1394_lock_exit, S1394_TNF_SL_ATREQ_STACK,
 885                     "");
 886                 return (DDI_FAILURE);
 887         }
 888 
 889         if (cmd->cmd_type == CMD1394_ASYNCH_LOCK_32) {
 890                 lock_type       = cmd->cmd_u.l32.lock_type;
 891                 num_retries     = cmd->cmd_u.l32.num_retries;
 892         } else {        /* (cmd->cmd_type == CMD1394_ASYNCH_LOCK_64) */
 893                 lock_type       = cmd->cmd_u.l64.lock_type;
 894                 num_retries     = cmd->cmd_u.l64.num_retries;
 895         }
 896 
 897         /* Make sure num_retries is reasonable */
 898         ASSERT(num_retries <= MAX_NUMBER_OF_LOCK_RETRIES);
 899 
 900         switch (lock_type) {
 901         case CMD1394_LOCK_MASK_SWAP:
 902         case CMD1394_LOCK_FETCH_ADD:
 903         case CMD1394_LOCK_LITTLE_ADD:
 904         case CMD1394_LOCK_BOUNDED_ADD:
 905         case CMD1394_LOCK_WRAP_ADD:
 906         case CMD1394_LOCK_COMPARE_SWAP:
 907                 ret = s1394_compare_swap(to_hal, target, cmd);
 908                 break;
 909 
 910         case CMD1394_LOCK_BIT_AND:
 911         case CMD1394_LOCK_BIT_OR:
 912         case CMD1394_LOCK_BIT_XOR:
 913         case CMD1394_LOCK_INCREMENT:
 914         case CMD1394_LOCK_DECREMENT:
 915         case CMD1394_LOCK_ADD:
 916         case CMD1394_LOCK_SUBTRACT:
 917         case CMD1394_LOCK_THRESH_ADD:
 918         case CMD1394_LOCK_THRESH_SUBTRACT:
 919         case CMD1394_LOCK_CLIP_ADD:
 920         case CMD1394_LOCK_CLIP_SUBTRACT:
 921                 ret = s1394_split_lock_req(to_hal, target, cmd);
 922                 break;
 923 
 924         default:
 925                 TNF_PROBE_1(t1394_lock_error, S1394_TNF_SL_ATREQ_ERROR, "",
 926                     tnf_string, msg, "Invalid lock_type in command");
 927                 cmd->cmd_result = CMD1394_EINVALID_COMMAND;
 928                 ret = DDI_FAILURE;
 929                 break;
 930         }
 931 
 932         TNF_PROBE_0_DEBUG(t1394_lock_exit, S1394_TNF_SL_ATREQ_STACK, "");
 933         return (ret);
 934 }
 935 
 936 /*
 937  * Function:    t1394_alloc_addr()
 938  * Input(s):    t1394_hdl               The target "handle" returned by
 939  *                                          t1394_attach()
 940  *              addr_allocp             The structure used to specify the type,
 941  *                                          size, permissions, and callbacks
 942  *                                          (if any) for the requested block
 943  *                                          of 1394 address space
 944  *              flags                   The flags parameter is unused (for now)
 945  *
 946  * Output(s):   result                  Used to pass more specific info back
 947  *                                          to target
 948  *
 949  * Description: t1394_alloc_addr() requests that part of the 1394 Address Space
 950  *              on the local node be set aside for this target driver, and
 951  *              associated with this address space should be some permissions
 952  *              and callbacks.  If the request is unable to be fulfilled,
 953  *              t1394_alloc_addr() will return DDI_FAILURE and result will
 954  *              indicate the reason.  T1394_EINVALID_PARAM indicates that the
 955  *              combination of flags given is invalid, and T1394_EALLOC_ADDR
 956  *              indicates that the requested type of address space is
 957  *              unavailable.
 958  */
 959 /* ARGSUSED */
 960 int
 961 t1394_alloc_addr(t1394_handle_t t1394_hdl, t1394_alloc_addr_t *addr_allocp,
 962     uint_t flags, int *result)
 963 {
 964         s1394_hal_t     *hal;
 965         s1394_target_t  *target;
 966         uint64_t        addr_lo;
 967         uint64_t        addr_hi;
 968         int             err;
 969 
 970         TNF_PROBE_0_DEBUG(t1394_alloc_addr_enter, S1394_TNF_SL_ARREQ_STACK,
 971             "");
 972 
 973         ASSERT(t1394_hdl != NULL);
 974         ASSERT(addr_allocp != NULL);
 975 
 976         target = (s1394_target_t *)t1394_hdl;
 977 
 978         /* Find the HAL this target resides on */
 979         hal = target->on_hal;
 980 
 981         /* Get the bounds of the request */
 982         addr_lo = addr_allocp->aa_address;
 983         addr_hi = addr_lo + addr_allocp->aa_length;
 984 
 985         /* Check combination of flags */
 986         if ((addr_allocp->aa_enable & T1394_ADDR_RDENBL) &&
 987             (addr_allocp->aa_evts.recv_read_request == NULL) &&
 988             (addr_allocp->aa_kmem_bufp == NULL)) {
 989                 if ((addr_allocp->aa_type != T1394_ADDR_FIXED)       ||
 990                     (addr_lo < hal->physical_addr_lo)             ||
 991                     (addr_hi > hal->physical_addr_hi)) {
 992 
 993                         /*
 994                          * Reads are enabled, but target doesn't want to
 995                          * be notified and hasn't given backing store
 996                          */
 997                         *result = T1394_EINVALID_PARAM;
 998 
 999                         TNF_PROBE_1(t1394_alloc_addr_error,
1000                             S1394_TNF_SL_ARREQ_ERROR, "", tnf_string, msg,
1001                             "Invalid flags "
1002                             "(RDs on, notify off, no backing store)");
1003                         TNF_PROBE_0_DEBUG(t1394_alloc_addr_exit,
1004                             S1394_TNF_SL_ARREQ_STACK, "");
1005 
1006                         /* kstats - addr alloc failures */
1007                         hal->hal_kstats->addr_alloc_fail++;
1008                         return (DDI_FAILURE);
1009                 } else {
1010                         addr_allocp->aa_enable &= ~T1394_ADDR_RDENBL;
1011                 }
1012         }
1013 
1014         if ((addr_allocp->aa_enable & T1394_ADDR_WRENBL) &&
1015             (addr_allocp->aa_evts.recv_write_request == NULL) &&
1016             (addr_allocp->aa_kmem_bufp == NULL)) {
1017                 if ((addr_allocp->aa_type != T1394_ADDR_FIXED)       ||
1018                     (addr_lo < hal->physical_addr_lo)             ||
1019                     (addr_hi > hal->physical_addr_hi)) {
1020 
1021                         /*
1022                          * Writes are enabled, but target doesn't want to
1023                          * be notified and hasn't given backing store
1024                          */
1025                         *result = T1394_EINVALID_PARAM;
1026 
1027                         TNF_PROBE_1(t1394_alloc_addr_error,
1028                             S1394_TNF_SL_ARREQ_ERROR, "", tnf_string, msg,
1029                             "Invalid flags "
1030                             "(WRs on, notify off, no backing store)");
1031                         TNF_PROBE_0_DEBUG(t1394_alloc_addr_exit,
1032                             S1394_TNF_SL_ARREQ_STACK, "");
1033 
1034                         /* kstats - addr alloc failures */
1035                         hal->hal_kstats->addr_alloc_fail++;
1036                         return (DDI_FAILURE);
1037                 } else {
1038                         addr_allocp->aa_enable &= ~T1394_ADDR_WRENBL;
1039                 }
1040         }
1041 
1042         if ((addr_allocp->aa_enable & T1394_ADDR_LKENBL) &&
1043             (addr_allocp->aa_evts.recv_lock_request == NULL) &&
1044             (addr_allocp->aa_kmem_bufp == NULL)) {
1045                 if ((addr_allocp->aa_type != T1394_ADDR_FIXED)       ||
1046                     (addr_lo < hal->physical_addr_lo)             ||
1047                     (addr_hi > hal->physical_addr_hi)) {
1048 
1049                         /*
1050                          * Locks are enabled, but target doesn't want to
1051                          * be notified and hasn't given backing store
1052                          */
1053                         *result = T1394_EINVALID_PARAM;
1054 
1055                         TNF_PROBE_1(t1394_alloc_addr_error,
1056                             S1394_TNF_SL_ARREQ_ERROR, "", tnf_string, msg,
1057                             "Invalid flags "
1058                             "(LKs on, notify off, no backing store)");
1059                         TNF_PROBE_0_DEBUG(t1394_alloc_addr_exit,
1060                             S1394_TNF_SL_ARREQ_STACK, "");
1061 
1062                         /* kstats - addr alloc failures */
1063                         hal->hal_kstats->addr_alloc_fail++;
1064                         return (DDI_FAILURE);
1065                 } else {
1066                         addr_allocp->aa_enable &= ~T1394_ADDR_LKENBL;
1067                 }
1068         }
1069 
1070         /* If not T1394_ADDR_FIXED, then allocate a block */
1071         if (addr_allocp->aa_type != T1394_ADDR_FIXED) {
1072                 err = s1394_request_addr_blk((s1394_hal_t *)target->on_hal,
1073                                         addr_allocp);
1074                 if (err != DDI_SUCCESS) {
1075                         *result = T1394_EALLOC_ADDR;
1076                         /* kstats - addr alloc failures */
1077                         hal->hal_kstats->addr_alloc_fail++;
1078                 } else {
1079                         *result = T1394_NOERROR;
1080                 }
1081                 TNF_PROBE_0_DEBUG(t1394_alloc_addr_exit,
1082                     S1394_TNF_SL_ARREQ_STACK, "");
1083                 return (err);
1084         } else {
1085                 err = s1394_claim_addr_blk((s1394_hal_t *)target->on_hal,
1086                                         addr_allocp);
1087                 if (err != DDI_SUCCESS) {
1088                         *result = T1394_EALLOC_ADDR;
1089                         /* kstats - addr alloc failures */
1090                         hal->hal_kstats->addr_alloc_fail++;
1091                 } else {
1092                         *result = T1394_NOERROR;
1093                         /* If physical, update the AR request counter */
1094                         if ((addr_lo >= hal->physical_addr_lo) &&
1095                             (addr_hi <= hal->physical_addr_hi)) {
1096                                 rw_enter(&hal->target_list_rwlock, RW_WRITER);
1097                                 target->physical_arreq_enabled++;
1098                                 rw_exit(&hal->target_list_rwlock);
1099 
1100                                 s1394_physical_arreq_set_one(target);
1101                         }
1102                 }
1103                 TNF_PROBE_0_DEBUG(t1394_alloc_addr_exit,
1104                     S1394_TNF_SL_ARREQ_STACK, "");
1105                 return (err);
1106         }
1107 }
1108 
1109 /*
1110  * Function:    t1394_free_addr()
1111  * Input(s):    t1394_hdl               The target "handle" returned by
1112  *                                          t1394_attach()
1113  *              addr_hdl                The address "handle" returned by the
1114  *                                         the t1394_alloc_addr() routine
1115  *              flags                   The flags parameter is unused (for now)
1116  *
1117  * Output(s):   DDI_SUCCESS             Target successfully freed memory
1118  *              DDI_FAILURE             Target failed to free the memory block
1119  *
1120  * Description: t1394_free_addr() attempts to free up memory that has been
1121  *              allocated by the target using t1394_alloc_addr().
1122  */
1123 /* ARGSUSED */
1124 int
1125 t1394_free_addr(t1394_handle_t t1394_hdl, t1394_addr_handle_t *addr_hdl,
1126     uint_t flags)
1127 {
1128         s1394_addr_space_blk_t  *curr_blk;
1129         s1394_hal_t             *hal;
1130         s1394_target_t          *target;
1131 
1132         TNF_PROBE_0_DEBUG(t1394_free_addr_enter, S1394_TNF_SL_ARREQ_STACK, "");
1133 
1134         ASSERT(t1394_hdl != NULL);
1135         ASSERT(addr_hdl != NULL);
1136 
1137         target = (s1394_target_t *)t1394_hdl;
1138 
1139         /* Find the HAL this target resides on */
1140         hal = target->on_hal;
1141 
1142         curr_blk = (s1394_addr_space_blk_t *)(*addr_hdl);
1143 
1144         if (s1394_free_addr_blk(hal, curr_blk) != DDI_SUCCESS) {
1145                 TNF_PROBE_0_DEBUG(t1394_free_addr_exit,
1146                     S1394_TNF_SL_ARREQ_STACK, "");
1147                 return (DDI_FAILURE);
1148         }
1149 
1150         /* If physical, update the AR request counter */
1151         if (curr_blk->addr_type == T1394_ADDR_FIXED) {
1152                 target->physical_arreq_enabled--;
1153                 s1394_physical_arreq_clear_one(target);
1154         }
1155 
1156         *addr_hdl = NULL;
1157 
1158         /* kstats - number of addr frees */
1159         hal->hal_kstats->addr_space_free++;
1160 
1161         TNF_PROBE_0_DEBUG(t1394_free_addr_exit, S1394_TNF_SL_ARREQ_STACK, "");
1162         return (DDI_SUCCESS);
1163 }
1164 
1165 /*
1166  * Function:    t1394_recv_request_done()
1167  * Input(s):    t1394_hdl               The target "handle" returned by
1168  *                                          t1394_attach()
1169  *              resp                    Pointer to the command which the
1170  *                                          target received in it's callback
1171  *              flags                   The flags parameter is unused (for now)
1172  *
1173  * Output(s):   DDI_SUCCESS             Target successfully returned command
1174  *                                          to the 1394 Software Framework,
1175  *                                          and, if necessary, sent response
1176  *              DDI_FAILURE             Target failed to return the command to
1177  *                                          the 1394 Software Framework
1178  *
1179  * Description: t1394_recv_request_done() takes the command that is given and
1180  *              determines whether that command requires a response to be
1181  *              sent on the 1394 bus.  If it is necessary and it's response
1182  *              code (cmd_result) has been set appropriately, then a response
1183  *              will be sent.  If no response is necessary (broadcast or
1184  *              posted write), then the command resources are reclaimed.
1185  */
1186 /* ARGSUSED */
1187 int
1188 t1394_recv_request_done(t1394_handle_t t1394_hdl, cmd1394_cmd_t *resp,
1189     uint_t flags)
1190 {
1191         s1394_hal_t      *hal;
1192         s1394_cmd_priv_t *s_priv;
1193         h1394_cmd_priv_t *h_priv;
1194         mblk_t           *curr_blk;
1195         size_t           msgb_len;
1196         size_t           size;
1197         int              ret;
1198         boolean_t        response = B_TRUE;
1199         boolean_t        posted_write = B_FALSE;
1200         boolean_t        write_cmd = B_FALSE;
1201         boolean_t        mblk_too_small;
1202 
1203         TNF_PROBE_0_DEBUG(t1394_recv_request_done_enter,
1204             S1394_TNF_SL_ARREQ_STACK, "");
1205 
1206         ASSERT(t1394_hdl != NULL);
1207         ASSERT(resp != NULL);
1208 
1209         /* Find the HAL this target resides on */
1210         hal = ((s1394_target_t *)t1394_hdl)->on_hal;
1211 
1212         /* Get the Services Layer private area */
1213         s_priv = S1394_GET_CMD_PRIV(resp);
1214 
1215         /* Get a pointer to the HAL private struct */
1216         h_priv = (h1394_cmd_priv_t *)&s_priv->hal_cmd_private;
1217 
1218         /* Is this an FA request? */
1219         if (s_priv->cmd_ext_type == S1394_CMD_EXT_FA) {
1220                 s1394_fa_convert_cmd(hal, resp);
1221         }
1222 
1223         /* Is this a write request? */
1224         if ((resp->cmd_type == CMD1394_ASYNCH_WR_QUAD) ||
1225             (resp->cmd_type == CMD1394_ASYNCH_WR_BLOCK)) {
1226                 write_cmd = B_TRUE;
1227                 /* Is this a posted write request? */
1228                 posted_write = s_priv->posted_write;
1229         }
1230 
1231         /* If broadcast or posted write cmd, don't send response */
1232         if ((resp->broadcast == 1) ||
1233             ((write_cmd == B_TRUE) && (posted_write == B_TRUE)))
1234                 response = B_FALSE;
1235 
1236         if (response == B_FALSE) {
1237                 if ((write_cmd == B_TRUE) && (posted_write == B_TRUE)) {
1238                         /* kstats - Posted Write error */
1239                         hal->hal_kstats->arreq_posted_write_error++;
1240                 }
1241 
1242                 /* Free the command - Pass it back to the HAL */
1243                 HAL_CALL(hal).response_complete(hal->halinfo.hal_private, resp,
1244                     h_priv);
1245                 TNF_PROBE_0_DEBUG(t1394_recv_request_done_exit,
1246                     S1394_TNF_SL_ARREQ_STACK, "");
1247                 return (DDI_SUCCESS);
1248         }
1249 
1250         ASSERT(response == B_TRUE);
1251 
1252         /* Verify valid response code */
1253         switch (resp->cmd_result) {
1254         case IEEE1394_RESP_COMPLETE:
1255                 /* Is the mblk_t too small? */
1256                 if (resp->cmd_type == CMD1394_ASYNCH_RD_BLOCK) {
1257                         curr_blk = resp->cmd_u.b.data_block;
1258                         size     = resp->cmd_u.b.blk_length;
1259                         msgb_len = 0;
1260                         mblk_too_small = B_TRUE;
1261 
1262                         if (curr_blk == NULL) {
1263                                 TNF_PROBE_1(t1394_recv_request_done_error,
1264                                     S1394_TNF_SL_ARREQ_ERROR, "", tnf_string,
1265                                     msg, "mblk_t is NULL in response");
1266                                 TNF_PROBE_0_DEBUG(t1394_recv_request_done_exit,
1267                                     S1394_TNF_SL_ARREQ_STACK, "");
1268                                 /*
1269                                  * Free the command - Pass it back
1270                                  * to the HAL
1271                                  */
1272                                 HAL_CALL(hal).response_complete(
1273                                     hal->halinfo.hal_private, resp, h_priv);
1274                                 ASSERT(curr_blk != NULL);
1275                                 return (DDI_FAILURE);
1276                         }
1277 
1278                         while (curr_blk != NULL) {
1279                                 msgb_len +=
1280                                     (curr_blk->b_wptr - curr_blk->b_rptr);
1281 
1282                                 if (msgb_len >= size) {
1283                                         mblk_too_small = B_FALSE;
1284                                         break;
1285                                 }
1286                                 curr_blk = curr_blk->b_cont;
1287                         }
1288 
1289                         if (mblk_too_small == B_TRUE) {
1290                                 TNF_PROBE_1(t1394_recv_request_done_error,
1291                                     S1394_TNF_SL_ARREQ_ERROR, "", tnf_string,
1292                                     msg, "mblk_t too small in response");
1293                                 TNF_PROBE_0_DEBUG(t1394_recv_request_done_exit,
1294                                     S1394_TNF_SL_ARREQ_STACK, "");
1295                                 /*
1296                                  * Free the command - Pass it back
1297                                  * to the HAL
1298                                  */
1299                                 HAL_CALL(hal).response_complete(
1300                                     hal->halinfo.hal_private, resp, h_priv);
1301                                 ASSERT(mblk_too_small != B_TRUE);
1302                                 return (DDI_FAILURE);
1303                         }
1304                 }
1305                 /* FALLTHROUGH */
1306         case IEEE1394_RESP_CONFLICT_ERROR:
1307         case IEEE1394_RESP_DATA_ERROR:
1308         case IEEE1394_RESP_TYPE_ERROR:
1309         case IEEE1394_RESP_ADDRESS_ERROR:
1310                 ret = s1394_send_response(hal, resp);
1311                 TNF_PROBE_0_DEBUG(t1394_recv_request_done_exit,
1312                     S1394_TNF_SL_ARREQ_STACK, "");
1313                 return (ret);
1314 
1315         default:
1316                 TNF_PROBE_1(t1394_recv_request_done_error,
1317                     S1394_TNF_SL_ARREQ_ERROR, "", tnf_string, msg,
1318                     "Invalid response code");
1319                 TNF_PROBE_0_DEBUG(t1394_recv_request_done_exit,
1320                     S1394_TNF_SL_ARREQ_STACK, "");
1321                 return (DDI_FAILURE);
1322         }
1323 }
1324 
1325 
1326 /*
1327  * Function:    t1394_fcp_register_controller()
1328  * Input(s):    t1394_hdl               The target "handle" returned by
1329  *                                          t1394_attach()
1330  *              evts                    The structure in which the target
1331  *                                          specifies its callback routines
1332  *
1333  *              flags                   The flags parameter is unused (for now)
1334  *
1335  * Output(s):   DDI_SUCCESS             Successfully registered.
1336  *
1337  *              DDI_FAILURE             Not registered due to failure.
1338  *
1339  * Description: Used to register the target within the Framework as an FCP
1340  *              controller.
1341  */
1342 /* ARGSUSED */
1343 int
1344 t1394_fcp_register_controller(t1394_handle_t t1394_hdl, t1394_fcp_evts_t *evts,
1345     uint_t flags)
1346 {
1347         int             result;
1348 
1349         TNF_PROBE_0_DEBUG(t1394_fcp_register_controller_enter,
1350             S1394_TNF_SL_FCP_STACK, "");
1351 
1352         ASSERT(t1394_hdl != NULL);
1353 
1354         result = s1394_fcp_register_ctl((s1394_target_t *)t1394_hdl, evts);
1355 
1356         TNF_PROBE_0_DEBUG(t1394_fcp_register_controller_exit,
1357             S1394_TNF_SL_FCP_STACK, "");
1358         return (result);
1359 }
1360 
1361 /*
1362  * Function:    t1394_fcp_unregister_controller()
1363  * Input(s):    t1394_hdl               The target "handle" returned by
1364  *                                          t1394_attach()
1365  *
1366  * Output(s):   DDI_SUCCESS             Successfully unregistered.
1367  *
1368  *              DDI_FAILURE             Not unregistered due to failure.
1369  *
1370  * Description: Used to unregister the target within the Framework as an FCP
1371  *              controller.
1372  */
1373 int
1374 t1394_fcp_unregister_controller(t1394_handle_t t1394_hdl)
1375 {
1376         int             result;
1377 
1378         TNF_PROBE_0_DEBUG(t1394_fcp_unregister_controller_enter,
1379             S1394_TNF_SL_FCP_STACK, "");
1380 
1381         ASSERT(t1394_hdl != NULL);
1382 
1383         result = s1394_fcp_unregister_ctl((s1394_target_t *)t1394_hdl);
1384 
1385         TNF_PROBE_0_DEBUG(t1394_fcp_unregister_controller_exit,
1386             S1394_TNF_SL_FCP_STACK, "");
1387         return (result);
1388 }
1389 
1390 /*
1391  * Function:    t1394_fcp_register_target()
1392  * Input(s):    t1394_hdl               The target "handle" returned by
1393  *                                          t1394_attach()
1394  *              evts                    The structure in which the target
1395  *                                          specifies its callback routines
1396  *
1397  *              flags                   The flags parameter is unused (for now)
1398  *
1399  * Output(s):   DDI_SUCCESS             Successfully registered.
1400  *
1401  *              DDI_FAILURE             Not registered due to failure.
1402  *
1403  * Description: Used to register the target within the Framework as an FCP
1404  *              target.
1405  */
1406 /* ARGSUSED */
1407 int
1408 t1394_fcp_register_target(t1394_handle_t t1394_hdl, t1394_fcp_evts_t *evts,
1409     uint_t flags)
1410 {
1411         int             result;
1412 
1413         TNF_PROBE_0_DEBUG(t1394_fcp_register_target_enter,
1414             S1394_TNF_SL_FCP_STACK, "");
1415 
1416         ASSERT(t1394_hdl != NULL);
1417 
1418         result = s1394_fcp_register_tgt((s1394_target_t *)t1394_hdl, evts);
1419 
1420         TNF_PROBE_0_DEBUG(t1394_fcp_register_target_exit,
1421             S1394_TNF_SL_FCP_STACK, "");
1422         return (result);
1423 }
1424 
1425 /*
1426  * Function:    t1394_fcp_unregister_target()
1427  * Input(s):    t1394_hdl               The target "handle" returned by
1428  *                                          t1394_attach()
1429  *
1430  * Output(s):   DDI_SUCCESS             Successfully unregistered.
1431  *
1432  *              DDI_FAILURE             Not unregistered due to failure.
1433  *
1434  * Description: Used to unregister the target within the Framework as an FCP
1435  *              target.
1436  */
1437 int
1438 t1394_fcp_unregister_target(t1394_handle_t t1394_hdl)
1439 {
1440         int             result;
1441 
1442         TNF_PROBE_0_DEBUG(t1394_fcp_unregister_target_enter,
1443             S1394_TNF_SL_FCP_STACK, "");
1444 
1445         ASSERT(t1394_hdl != NULL);
1446 
1447         result = s1394_fcp_unregister_tgt((s1394_target_t *)t1394_hdl);
1448 
1449         TNF_PROBE_0_DEBUG(t1394_fcp_unregister_target_exit,
1450             S1394_TNF_SL_FCP_STACK, "");
1451         return (result);
1452 }
1453 
1454 /*
1455  * Function:    t1394_cmp_register()
1456  * Input(s):    t1394_hdl               The target "handle" returned by
1457  *                                          t1394_attach()
1458  *              evts                    The structure in which the target
1459  *                                          specifies its callback routines
1460  *
1461  * Output(s):   DDI_SUCCESS             Successfully registered.
1462  *
1463  *              DDI_FAILURE             Not registered due to failure.
1464  *
1465  * Description: Used to register the target within the Framework as a CMP
1466  *              device.
1467  */
1468 /* ARGSUSED */
1469 int
1470 t1394_cmp_register(t1394_handle_t t1394_hdl, t1394_cmp_evts_t *evts,
1471     uint_t flags)
1472 {
1473         int             result;
1474 
1475         TNF_PROBE_0_DEBUG(t1394_cmp_register_enter, S1394_TNF_SL_CMP_STACK, "");
1476 
1477         ASSERT(t1394_hdl != NULL);
1478 
1479         result = s1394_cmp_register((s1394_target_t *)t1394_hdl, evts);
1480 
1481         TNF_PROBE_0_DEBUG(t1394_cmp_register_exit, S1394_TNF_SL_CMP_STACK, "");
1482         return (result);
1483 }
1484 
1485 /*
1486  * Function:    t1394_cmp_unregister()
1487  * Input(s):    t1394_hdl               The target "handle" returned by
1488  *                                          t1394_attach()
1489  *              evts                    The structure in which the target
1490  *                                          specifies its callback routines
1491  *
1492  * Output(s):   DDI_SUCCESS             Successfully registered.
1493  *
1494  *              DDI_FAILURE             Not registered due to failure.
1495  *
1496  * Description: Used to unregister the target within the Framework as a CMP
1497  *              device.
1498  */
1499 int
1500 t1394_cmp_unregister(t1394_handle_t t1394_hdl)
1501 {
1502         int             result;
1503 
1504         TNF_PROBE_0_DEBUG(t1394_cmp_unregister_enter, S1394_TNF_SL_CMP_STACK,
1505             "");
1506 
1507         ASSERT(t1394_hdl != NULL);
1508 
1509         result = s1394_cmp_unregister((s1394_target_t *)t1394_hdl);
1510 
1511         TNF_PROBE_0_DEBUG(t1394_cmp_unregister_exit, S1394_TNF_SL_CMP_STACK,
1512             "");
1513         return (result);
1514 }
1515 
1516 /*
1517  * Function:    t1394_cmp_read()
1518  * Input(s):    t1394_hdl               The target "handle" returned by
1519  *                                          t1394_attach()
1520  *              reg                     Register type.
1521  *              valp                    Returned register value.
1522  *
1523  * Output(s):   DDI_SUCCESS             Successfully registered.
1524  *
1525  *              DDI_FAILURE             Not registered due to failure.
1526  *
1527  * Description: Used to read a CMP register value.
1528  */
1529 int
1530 t1394_cmp_read(t1394_handle_t t1394_hdl, t1394_cmp_reg_t reg, uint32_t *valp)
1531 {
1532         int             result;
1533 
1534         TNF_PROBE_0_DEBUG(t1394_cmp_read_enter, S1394_TNF_SL_CMP_STACK, "");
1535 
1536         ASSERT(t1394_hdl != NULL);
1537 
1538         result = s1394_cmp_read((s1394_target_t *)t1394_hdl, reg, valp);
1539 
1540         TNF_PROBE_0_DEBUG(t1394_cmp_read_exit, S1394_TNF_SL_CMP_STACK, "");
1541         return (result);
1542 }
1543 
1544 /*
1545  * Function:    t1394_cmp_cas()
1546  * Input(s):    t1394_hdl               The target "handle" returned by
1547  *                                          t1394_attach()
1548  *              reg                     Register type.
1549  *              arg_val                 Compare argument.
1550  *              new_val                 New register value.
1551  *              old_valp                Returned original register value.
1552  *
1553  * Output(s):   DDI_SUCCESS             Successfully registered.
1554  *
1555  *              DDI_FAILURE             Not registered due to failure.
1556  *
1557  * Description: Used to compare-swap a CMP register value.
1558  */
1559 int
1560 t1394_cmp_cas(t1394_handle_t t1394_hdl, t1394_cmp_reg_t reg, uint32_t arg_val,
1561     uint32_t new_val, uint32_t *old_valp)
1562 {
1563         int             result;
1564 
1565         TNF_PROBE_0_DEBUG(t1394_cmp_read_enter, S1394_TNF_SL_CMP_STACK, "");
1566 
1567         ASSERT(t1394_hdl != NULL);
1568 
1569         result = s1394_cmp_cas((s1394_target_t *)t1394_hdl, reg, arg_val,
1570                                 new_val, old_valp);
1571 
1572         TNF_PROBE_0_DEBUG(t1394_cmp_read_exit, S1394_TNF_SL_CMP_STACK, "");
1573         return (result);
1574 }
1575 
1576 /*
1577  * Function:    t1394_alloc_isoch_single()
1578  * Input(s):    t1394_hdl               The target "handle" returned by
1579  *                                          t1394_attach()
1580  *              sii                     The structure used to set up the
1581  *                                          overall characteristics of the
1582  *                                          isochronous stream
1583  *              flags                   The flags parameter is unused (for now)
1584  *
1585  * Output(s):   setup_args              Contains the channel number that was
1586  *                                          allocated
1587  *              t1394_single_hdl        This in the isoch "handle" used in
1588  *                                          t1394_free_isoch_single()
1589  *              result                  Used to pass more specific info back
1590  *                                          to target
1591  *
1592  * Description: t1394_alloc_isoch_single() is used to direct the 1394 Software
1593  *              Framework to allocate an isochronous channel and bandwidth
1594  *              from the Isochronous Resource Manager (IRM).  If a bus reset
1595  *              occurs, the 1394 Software Framework attempts to reallocate the
1596  *              same resources, calling the rsrc_fail_target() callback if
1597  *              it is unsuccessful.
1598  */
1599 /* ARGSUSED */
1600 int
1601 t1394_alloc_isoch_single(t1394_handle_t t1394_hdl,
1602     t1394_isoch_singleinfo_t *sii, uint_t flags,
1603     t1394_isoch_single_out_t *output_args,
1604     t1394_isoch_single_handle_t *t1394_single_hdl, int *result)
1605 {
1606         s1394_hal_t             *hal;
1607         s1394_isoch_cec_t       *cec_new;
1608         t1394_join_isochinfo_t  jii;
1609         int                     ret;
1610         int                     err;
1611 
1612         TNF_PROBE_0_DEBUG(t1394_alloc_isoch_single_enter,
1613             S1394_TNF_SL_ISOCH_STACK, "");
1614 
1615         ASSERT(t1394_hdl != NULL);
1616         ASSERT(t1394_single_hdl != NULL);
1617         ASSERT(sii != NULL);
1618 
1619         hal = ((s1394_target_t *)t1394_hdl)->on_hal;
1620 
1621         /* Check for invalid channel_mask */
1622         if (sii->si_channel_mask == 0) {
1623                 TNF_PROBE_1(t1394_alloc_isoch_single_error,
1624                     S1394_TNF_SL_ISOCH_ERROR, "", tnf_string, msg,
1625                     "Invalid channel mask");
1626                 TNF_PROBE_0_DEBUG(t1394_alloc_isoch_single_exit,
1627                     S1394_TNF_SL_ISOCH_STACK, "");
1628                 return (DDI_FAILURE);
1629         }
1630 
1631         /* Check for invalid bandwidth */
1632         if ((sii->si_bandwidth <= IEEE1394_BANDWIDTH_MIN) ||
1633             (sii->si_bandwidth > IEEE1394_BANDWIDTH_MAX)) {
1634                 TNF_PROBE_1(t1394_alloc_isoch_single_error,
1635                     S1394_TNF_SL_ISOCH_ERROR, "", tnf_string, msg,
1636                     "Invalid bandwidth requirements");
1637                 TNF_PROBE_0_DEBUG(t1394_alloc_isoch_single_exit,
1638                     S1394_TNF_SL_ISOCH_STACK, "");
1639                 return (DDI_FAILURE);
1640         }
1641 
1642         /* Verify that rsrc_fail_target() callback is non-NULL */
1643         if (sii->rsrc_fail_target == NULL) {
1644                 TNF_PROBE_1(t1394_alloc_isoch_single_error,
1645                     S1394_TNF_SL_ISOCH_ERROR, "", tnf_string, msg,
1646                     "Invalid callback specified");
1647                 TNF_PROBE_0_DEBUG(t1394_alloc_isoch_single_exit,
1648                     S1394_TNF_SL_ISOCH_STACK, "");
1649                 return (DDI_FAILURE);
1650         }
1651 
1652         /*
1653          * Allocate an Isoch CEC of type S1394_SINGLE
1654          */
1655 
1656         /* Allocate the Isoch CEC structure */
1657         cec_new = kmem_zalloc(sizeof (s1394_isoch_cec_t), KM_SLEEP);
1658 
1659         /* Initialize the structure type */
1660         cec_new->cec_type = S1394_SINGLE;
1661 
1662         /* Create the mutex and "in_callbacks" cv */
1663         mutex_init(&cec_new->isoch_cec_mutex, NULL, MUTEX_DRIVER,
1664             hal->halinfo.hw_interrupt);
1665         cv_init(&cec_new->in_callbacks_cv, NULL, CV_DRIVER,
1666             hal->halinfo.hw_interrupt);
1667 
1668         /* Initialize the Isoch CEC's member list */
1669         cec_new->cec_member_list_head = NULL;
1670         cec_new->cec_member_list_tail = NULL;
1671 
1672         /* Initialize the filters */
1673         cec_new->filter_min_speed    = sii->si_speed;
1674         cec_new->filter_max_speed    = sii->si_speed;
1675         cec_new->filter_current_speed        = cec_new->filter_max_speed;
1676         cec_new->filter_channel_mask = sii->si_channel_mask;
1677         cec_new->bandwidth           = sii->si_bandwidth;
1678         cec_new->state_transitions   = ISOCH_CEC_FREE | ISOCH_CEC_JOIN |
1679                                             ISOCH_CEC_SETUP;
1680 
1681         mutex_enter(&hal->isoch_cec_list_mutex);
1682 
1683         /* Insert Isoch CEC into the HAL's list */
1684         s1394_isoch_cec_list_insert(hal, cec_new);
1685 
1686         mutex_exit(&hal->isoch_cec_list_mutex);
1687 
1688         /*
1689          * Join the newly created Isoch CEC
1690          */
1691         jii.req_channel_mask    = sii->si_channel_mask;
1692         jii.req_max_speed       = sii->si_speed;
1693         jii.jii_options         = T1394_TALKER;
1694         jii.isoch_cec_evts_arg  = sii->single_evt_arg;
1695 
1696         /* All events are NULL except rsrc_fail_target() */
1697         jii.isoch_cec_evts.setup_target     = NULL;
1698         jii.isoch_cec_evts.start_target     = NULL;
1699         jii.isoch_cec_evts.stop_target      = NULL;
1700         jii.isoch_cec_evts.stop_target      = NULL;
1701         jii.isoch_cec_evts.teardown_target  = NULL;
1702         jii.isoch_cec_evts.rsrc_fail_target = sii->rsrc_fail_target;
1703 
1704         ret = t1394_join_isoch_cec(t1394_hdl,
1705             (t1394_isoch_cec_handle_t)cec_new, 0, &jii);
1706 
1707         if (ret != DDI_SUCCESS) {
1708                 TNF_PROBE_1(t1394_alloc_isoch_single_error,
1709                     S1394_TNF_SL_ISOCH_ERROR, "", tnf_string, msg,
1710                     "Unexpected error from t1394_join_isoch_cec()");
1711 
1712                 ret = t1394_free_isoch_cec(t1394_hdl, flags,
1713                     (t1394_isoch_cec_handle_t *)&cec_new);
1714                 if (ret != DDI_SUCCESS) {
1715                         /* Unable to free the Isoch CEC */
1716                         TNF_PROBE_1(t1394_alloc_isoch_single_error,
1717                             S1394_TNF_SL_ISOCH_ERROR, "", tnf_string, msg,
1718                             "Unexpected error from t1394_free_isoch_cec()");
1719                         ASSERT(0);
1720                 }
1721 
1722                 /* Handle is nulled out before returning */
1723                 *t1394_single_hdl = NULL;
1724 
1725                 TNF_PROBE_0_DEBUG(t1394_alloc_isoch_single_exit,
1726                     S1394_TNF_SL_ISOCH_STACK, "");
1727                 return (DDI_FAILURE);
1728         }
1729 
1730         /*
1731          * Setup the isoch resources, etc.
1732          */
1733         ret = t1394_setup_isoch_cec(t1394_hdl,
1734             (t1394_isoch_cec_handle_t)cec_new, 0, &err);
1735 
1736         if (ret != DDI_SUCCESS) {
1737                 TNF_PROBE_1(t1394_alloc_isoch_single_error,
1738                     S1394_TNF_SL_ISOCH_ERROR, "", tnf_string, msg,
1739                     "Unexpected error from t1394_setup_isoch_cec()");
1740 
1741                 *result = err;
1742 
1743                 /* Leave the Isoch CEC */
1744                 ret = t1394_leave_isoch_cec(t1394_hdl,
1745                     (t1394_isoch_cec_handle_t)cec_new, 0);
1746                 if (ret != DDI_SUCCESS) {
1747                         /* Unable to leave the Isoch CEC */
1748                         TNF_PROBE_1(t1394_alloc_isoch_single_error,
1749                             S1394_TNF_SL_ISOCH_ERROR, "", tnf_string, msg,
1750                             "Unexpected error from t1394_leave_isoch_cec()");
1751                         ASSERT(0);
1752                 }
1753 
1754                 /* Free up the Isoch CEC */
1755                 ret = t1394_free_isoch_cec(t1394_hdl, flags,
1756                     (t1394_isoch_cec_handle_t *)&cec_new);
1757                 if (ret != DDI_SUCCESS) {
1758                         /* Unable to free the Isoch CEC */
1759                         TNF_PROBE_1(t1394_alloc_isoch_single_error,
1760                             S1394_TNF_SL_ISOCH_ERROR, "", tnf_string, msg,
1761                             "Unexpected error from t1394_free_isoch_cec()");
1762                         ASSERT(0);
1763                 }
1764 
1765                 /* Handle is nulled out before returning */
1766                 *t1394_single_hdl = NULL;
1767 
1768                 TNF_PROBE_0_DEBUG(t1394_alloc_isoch_single_exit,
1769                     S1394_TNF_SL_ISOCH_STACK, "");
1770                 return (DDI_FAILURE);
1771         }
1772 
1773         /* Return the setup_args - channel num and speed */
1774         mutex_enter(&cec_new->isoch_cec_mutex);
1775         output_args->channel_num  = cec_new->realloc_chnl_num;
1776         mutex_exit(&cec_new->isoch_cec_mutex);
1777 
1778         /* Update the handle */
1779         *t1394_single_hdl = (t1394_isoch_single_handle_t)cec_new;
1780 
1781         TNF_PROBE_0_DEBUG(t1394_alloc_isoch_single_exit,
1782             S1394_TNF_SL_ISOCH_STACK, "");
1783         return (DDI_SUCCESS);
1784 }
1785 
1786 /*
1787  * Function:    t1394_free_isoch_single()
1788  * Input(s):    t1394_hdl               The target "handle" returned by
1789  *                                          t1394_attach()
1790  *              t1394_single_hdl        The isoch "handle" return by
1791  *                                          t1394_alloc_isoch_single()
1792  *              flags                   The flags parameter is unused (for now)
1793  *
1794  * Output(s):   None
1795  *
1796  * Description: t1394_free_isoch_single() frees the isochronous resources
1797  *              and the handle that were allocated during the call to
1798  *              t1394_alloc_isoch_single().
1799  */
1800 /* ARGSUSED */
1801 void
1802 t1394_free_isoch_single(t1394_handle_t t1394_hdl,
1803     t1394_isoch_single_handle_t *t1394_single_hdl, uint_t flags)
1804 {
1805         s1394_isoch_cec_t *cec_curr;
1806         int               ret;
1807 
1808         TNF_PROBE_0_DEBUG(t1394_free_isoch_single_enter,
1809             S1394_TNF_SL_ISOCH_STACK, "");
1810 
1811         ASSERT(t1394_hdl != NULL);
1812         ASSERT(t1394_single_hdl != NULL);
1813 
1814         /* Convert the handle to an Isoch CEC pointer */
1815         cec_curr = (s1394_isoch_cec_t *)(*t1394_single_hdl);
1816 
1817         /*
1818          * Teardown the isoch resources, etc.
1819          */
1820         ret = t1394_teardown_isoch_cec(t1394_hdl,
1821             (t1394_isoch_cec_handle_t)cec_curr, 0);
1822         if (ret != DDI_SUCCESS) {
1823                 /* Unable to teardown the Isoch CEC */
1824                 TNF_PROBE_1(t1394_free_isoch_single_error,
1825                     S1394_TNF_SL_ISOCH_ERROR, "", tnf_string, msg,
1826                     "Unexpected error from t1394_teardown_isoch_cec()");
1827                 ASSERT(0);
1828         }
1829 
1830         /*
1831          * Leave the Isoch CEC
1832          */
1833         ret = t1394_leave_isoch_cec(t1394_hdl,
1834             (t1394_isoch_cec_handle_t)cec_curr, 0);
1835         if (ret != DDI_SUCCESS) {
1836                 /* Unable to leave the Isoch CEC */
1837                 TNF_PROBE_1(t1394_free_isoch_single_error,
1838                     S1394_TNF_SL_ISOCH_ERROR, "", tnf_string, msg,
1839                     "Unexpected error from t1394_leave_isoch_cec()");
1840                 ASSERT(0);
1841         }
1842 
1843         /*
1844          * Free the Isoch CEC
1845          */
1846         ret = t1394_free_isoch_cec(t1394_hdl, flags,
1847             (t1394_isoch_cec_handle_t *)&cec_curr);
1848         if (ret != DDI_SUCCESS) {
1849                 /* Unable to free the Isoch CEC */
1850                 TNF_PROBE_1(t1394_free_isoch_single_error,
1851                     S1394_TNF_SL_ISOCH_ERROR, "", tnf_string, msg,
1852                     "Unexpected error from t1394_free_isoch_cec()");
1853                 ASSERT(0);
1854         }
1855 
1856         /* Handle is nulled out before returning */
1857         *t1394_single_hdl = NULL;
1858 
1859         TNF_PROBE_0_DEBUG(t1394_free_isoch_single_exit,
1860             S1394_TNF_SL_ISOCH_STACK, "");
1861 }
1862 
1863 /*
1864  * Function:    t1394_alloc_isoch_cec()
1865  * Input(s):    t1394_hdl               The target "handle" returned by
1866  *                                          t1394_attach()
1867  *              props                   The structure used to set up the
1868  *                                          overall characteristics of for
1869  *                                          the Isoch CEC.
1870  *              flags                   The flags parameter is unused (for now)
1871  *
1872  * Output(s):   t1394_isoch_cec_hdl     The Isoch CEC "handle" used in all
1873  *                                          subsequent isoch_cec() calls
1874  *
1875  * Description: t1394_alloc_isoch_cec() allocates and initializes an
1876  *              isochronous channel event coordinator (Isoch CEC) for use
1877  *              in managing and coordinating activity for an isoch channel
1878  */
1879 /* ARGSUSED */
1880 int
1881 t1394_alloc_isoch_cec(t1394_handle_t t1394_hdl, t1394_isoch_cec_props_t *props,
1882     uint_t flags, t1394_isoch_cec_handle_t *t1394_isoch_cec_hdl)
1883 {
1884         s1394_hal_t       *hal;
1885         s1394_isoch_cec_t *cec_new;
1886         uint64_t          temp;
1887 
1888         TNF_PROBE_0_DEBUG(t1394_alloc_isoch_cec_enter,
1889             S1394_TNF_SL_ISOCH_STACK, "");
1890 
1891         ASSERT(t1394_hdl != NULL);
1892         ASSERT(t1394_isoch_cec_hdl != NULL);
1893         ASSERT(props != NULL);
1894 
1895         hal = ((s1394_target_t *)t1394_hdl)->on_hal;
1896 
1897         /* Check for invalid channel_mask */
1898         if (props->cec_channel_mask == 0) {
1899                 TNF_PROBE_1(t1394_alloc_isoch_cec_error,
1900                     S1394_TNF_SL_ISOCH_ERROR, "", tnf_string, msg,
1901                     "Invalid channel mask");
1902                 TNF_PROBE_0_DEBUG(t1394_alloc_isoch_cec_exit,
1903                     S1394_TNF_SL_ISOCH_STACK, "");
1904                 return (DDI_FAILURE);
1905         }
1906 
1907         /* Test conditions specific to T1394_NO_IRM_ALLOC */
1908         temp = props->cec_channel_mask;
1909         if (props->cec_options & T1394_NO_IRM_ALLOC) {
1910                 /* If T1394_NO_IRM_ALLOC, then only one bit should be set */
1911                 if (!ISP2(temp)) {
1912                         TNF_PROBE_1(t1394_alloc_isoch_cec_error,
1913                             S1394_TNF_SL_ISOCH_ERROR, "", tnf_string, msg,
1914                             "Invalid channel mask");
1915                         TNF_PROBE_0_DEBUG(t1394_alloc_isoch_cec_exit,
1916                             S1394_TNF_SL_ISOCH_STACK, "");
1917                         return (DDI_FAILURE);
1918                 }
1919 
1920                 /* If T1394_NO_IRM_ALLOC, then speeds should be equal */
1921                 if (props->cec_min_speed != props->cec_max_speed) {
1922                         TNF_PROBE_1(t1394_alloc_isoch_cec_error,
1923                             S1394_TNF_SL_ISOCH_ERROR, "", tnf_string, msg,
1924                             "Invalid speeds (min != max)");
1925                         TNF_PROBE_0_DEBUG(t1394_alloc_isoch_cec_exit,
1926                             S1394_TNF_SL_ISOCH_STACK, "");
1927                         return (DDI_FAILURE);
1928                 }
1929         }
1930 
1931         /* Check for invalid bandwidth */
1932         if ((props->cec_bandwidth <= IEEE1394_BANDWIDTH_MIN) ||
1933             (props->cec_bandwidth > IEEE1394_BANDWIDTH_MAX)) {
1934                 TNF_PROBE_1(t1394_alloc_isoch_cec_error,
1935                     S1394_TNF_SL_ISOCH_ERROR, "", tnf_string, msg,
1936                     "Invalid bandwidth requirements");
1937                 TNF_PROBE_0_DEBUG(t1394_alloc_isoch_cec_exit,
1938                     S1394_TNF_SL_ISOCH_STACK, "");
1939                 return (DDI_FAILURE);
1940         }
1941 
1942         /* Allocate the Isoch CEC structure */
1943         cec_new = kmem_zalloc(sizeof (s1394_isoch_cec_t), KM_SLEEP);
1944 
1945         /* Initialize the structure type */
1946         cec_new->cec_type = S1394_PEER_TO_PEER;
1947 
1948         /* Create the mutex and "in_callbacks" cv */
1949         mutex_init(&cec_new->isoch_cec_mutex, NULL, MUTEX_DRIVER,
1950             hal->halinfo.hw_interrupt);
1951         cv_init(&cec_new->in_callbacks_cv, NULL, CV_DRIVER,
1952             hal->halinfo.hw_interrupt);
1953 
1954         /* Initialize the Isoch CEC's member list */
1955         cec_new->cec_member_list_head        = NULL;
1956         cec_new->cec_member_list_tail        = NULL;
1957 
1958         /* Initialize the filters */
1959         cec_new->filter_min_speed    = props->cec_min_speed;
1960         cec_new->filter_max_speed    = props->cec_max_speed;
1961         cec_new->filter_current_speed        = cec_new->filter_max_speed;
1962         cec_new->filter_channel_mask = props->cec_channel_mask;
1963         cec_new->bandwidth           = props->cec_bandwidth;
1964         cec_new->cec_options         = props->cec_options;
1965         cec_new->state_transitions   = ISOCH_CEC_FREE | ISOCH_CEC_JOIN |
1966                                             ISOCH_CEC_SETUP;
1967 
1968         mutex_enter(&hal->isoch_cec_list_mutex);
1969 
1970         /* Insert Isoch CEC into the HAL's list */
1971         s1394_isoch_cec_list_insert(hal, cec_new);
1972 
1973         mutex_exit(&hal->isoch_cec_list_mutex);
1974 
1975         /* Update the handle and return */
1976         *t1394_isoch_cec_hdl = (t1394_isoch_cec_handle_t)cec_new;
1977 
1978         TNF_PROBE_0_DEBUG(t1394_alloc_isoch_cec_exit,
1979             S1394_TNF_SL_ISOCH_STACK, "");
1980         return (DDI_SUCCESS);
1981 }
1982 
1983 /*
1984  * Function:    t1394_free_isoch_cec()
1985  * Input(s):    t1394_hdl               The target "handle" returned by
1986  *                                          t1394_attach()
1987  *              flags                   The flags parameter is unused (for now)
1988  *              t1394_isoch_cec_hdl     The Isoch CEC "handle" returned by
1989  *                                          t1394_alloc_isoch_cec()
1990  *
1991  * Output(s):   DDI_SUCCESS             Target successfully freed the Isoch CEC
1992  *              DDI_FAILURE             Target failed to free the Isoch CEC
1993  *
1994  * Description: t1394_free_isoch_cec() attempts to free the Isoch CEC
1995  *              structure.  It will fail (DDI_FAILURE) if there are any
1996  *              remaining members who have not yet left.
1997  */
1998 /* ARGSUSED */
1999 int
2000 t1394_free_isoch_cec(t1394_handle_t t1394_hdl, uint_t flags,
2001     t1394_isoch_cec_handle_t *t1394_isoch_cec_hdl)
2002 {
2003         s1394_hal_t       *hal;
2004         s1394_isoch_cec_t *cec_curr;
2005 
2006         TNF_PROBE_0_DEBUG(t1394_free_isoch_cec_enter,
2007             S1394_TNF_SL_ISOCH_STACK, "");
2008 
2009         ASSERT(t1394_hdl != NULL);
2010         ASSERT(t1394_isoch_cec_hdl != NULL);
2011 
2012         hal = ((s1394_target_t *)t1394_hdl)->on_hal;
2013 
2014         /* Convert the handle to an Isoch CEC pointer */
2015         cec_curr = (s1394_isoch_cec_t *)(*t1394_isoch_cec_hdl);
2016 
2017         /* Lock the Isoch CEC member list */
2018         mutex_enter(&cec_curr->isoch_cec_mutex);
2019 
2020         /* Are we in any callbacks? */
2021         if (CEC_IN_ANY_CALLBACKS(cec_curr)) {
2022                 /* Unlock the Isoch CEC member list */
2023                 mutex_exit(&cec_curr->isoch_cec_mutex);
2024                 TNF_PROBE_1(t1394_free_isoch_cec_error,
2025                     S1394_TNF_SL_ISOCH_ERROR, "", tnf_string, msg,
2026                     "Not allowed to free Isoch CEC (in callbacks)");
2027                 TNF_PROBE_0_DEBUG(t1394_free_isoch_cec_exit,
2028                     S1394_TNF_SL_ISOCH_STACK, "");
2029                 return (DDI_FAILURE);
2030         }
2031 
2032         /* Is "free" a legal state transition? */
2033         if (CEC_TRANSITION_LEGAL(cec_curr, ISOCH_CEC_FREE) == 0) {
2034                 /* Unlock the Isoch CEC member list */
2035                 mutex_exit(&cec_curr->isoch_cec_mutex);
2036                 TNF_PROBE_1(t1394_free_isoch_cec_error,
2037                     S1394_TNF_SL_ISOCH_ERROR, "", tnf_string, msg,
2038                     "Not allowed to free Isoch CEC");
2039                 TNF_PROBE_0_DEBUG(t1394_free_isoch_cec_exit,
2040                     S1394_TNF_SL_ISOCH_STACK, "");
2041                 return (DDI_FAILURE);
2042         }
2043         mutex_exit(&cec_curr->isoch_cec_mutex);
2044 
2045         mutex_enter(&hal->isoch_cec_list_mutex);
2046 
2047         /* Remove Isoch CEC from HAL's list */
2048         s1394_isoch_cec_list_remove(hal, cec_curr);
2049 
2050         mutex_exit(&hal->isoch_cec_list_mutex);
2051 
2052         /* Destroy the Isoch CEC's mutex and cv */
2053         cv_destroy(&cec_curr->in_callbacks_cv);
2054         mutex_destroy(&cec_curr->isoch_cec_mutex);
2055 
2056         /* Free up the memory for the Isoch CEC struct */
2057         kmem_free(cec_curr, sizeof (s1394_isoch_cec_t));
2058 
2059         /* Update the handle and return */
2060         *t1394_isoch_cec_hdl = NULL;
2061 
2062         TNF_PROBE_0_DEBUG(t1394_free_isoch_cec_exit,
2063             S1394_TNF_SL_ISOCH_STACK, "");
2064         return (DDI_SUCCESS);
2065 }
2066 
2067 /*
2068  * Function:    t1394_join_isoch_cec()
2069  * Input(s):    t1394_hdl               The target "handle" returned by
2070  *                                          t1394_attach()
2071  *              t1394_isoch_cec_hdl     The Isoch CEC "handle" returned by
2072  *                                          t1394_alloc_isoch_cec()
2073  *              flags                   The flags parameter is unused (for now)
2074  *              join_isoch_info         This structure provides infomation
2075  *                                          about a target that wishes to join
2076  *                                          the given Isoch CEC.  It gives
2077  *                                          max_speed, channel_mask, etc.
2078  *
2079  * Output(s):   DDI_SUCCESS             Target successfully joined the
2080  *                                          Isoch CEC
2081  *              DDI_FAILURE             Target failed to join the Isoch CEC
2082  *
2083  * Description: t1394_join_isoch_cec() determines, based on the information
2084  *              given in the join_isoch_info structure, if the target may
2085  *              join the Isoch CEC.  If it is determined that the target may
2086  *              join, the specified callback routines are stored away for
2087  *              later use in the coordination tasks.
2088  */
2089 /* ARGSUSED */
2090 int
2091 t1394_join_isoch_cec(t1394_handle_t t1394_hdl,
2092     t1394_isoch_cec_handle_t t1394_isoch_cec_hdl, uint_t flags,
2093     t1394_join_isochinfo_t *join_isoch_info)
2094 {
2095         s1394_hal_t              *hal;
2096         s1394_isoch_cec_t        *cec_curr;
2097         s1394_isoch_cec_member_t *member_new;
2098         uint64_t                 check_mask;
2099         uint_t                   curr_max_speed;
2100 
2101         TNF_PROBE_0_DEBUG(t1394_join_isoch_cec_enter,
2102             S1394_TNF_SL_ISOCH_STACK, "");
2103 
2104         ASSERT(t1394_hdl != NULL);
2105         ASSERT(t1394_isoch_cec_hdl != NULL);
2106 
2107         hal = ((s1394_target_t *)t1394_hdl)->on_hal;
2108 
2109         /* Convert the handle to an Isoch CEC pointer */
2110         cec_curr = (s1394_isoch_cec_t *)t1394_isoch_cec_hdl;
2111 
2112         /* Allocate a new Isoch CEC member structure */
2113         member_new = kmem_zalloc(sizeof (s1394_isoch_cec_member_t), KM_SLEEP);
2114 
2115         /* Lock the Isoch CEC member list */
2116         mutex_enter(&cec_curr->isoch_cec_mutex);
2117 
2118         /* Are we in any callbacks? (Wait for them to finish) */
2119         while (CEC_IN_ANY_CALLBACKS(cec_curr)) {
2120                 cec_curr->cec_want_wakeup = B_TRUE;
2121                 cv_wait(&cec_curr->in_callbacks_cv,
2122                     &cec_curr->isoch_cec_mutex);
2123         }
2124 
2125         /* Is "join" a legal state transition? */
2126         if (CEC_TRANSITION_LEGAL(cec_curr, ISOCH_CEC_JOIN) == 0) {
2127                 kmem_free(member_new, sizeof (s1394_isoch_cec_member_t));
2128                 /* Unlock the Isoch CEC member list */
2129                 mutex_exit(&cec_curr->isoch_cec_mutex);
2130                 TNF_PROBE_1(t1394_join_isoch_cec_error,
2131                     S1394_TNF_SL_ISOCH_ERROR, "", tnf_string, msg,
2132                     "Not allowed to join Isoch CEC");
2133                 TNF_PROBE_0_DEBUG(t1394_join_isoch_cec_exit,
2134                     S1394_TNF_SL_ISOCH_STACK, "");
2135                 return (DDI_FAILURE);
2136         }
2137 
2138         /* Check the channel mask for consistency */
2139         check_mask = join_isoch_info->req_channel_mask &
2140             cec_curr->filter_channel_mask;
2141         if (check_mask == 0) {
2142                 kmem_free(member_new, sizeof (s1394_isoch_cec_member_t));
2143                 /* Unlock the Isoch CEC member list */
2144                 mutex_exit(&cec_curr->isoch_cec_mutex);
2145                 TNF_PROBE_1(t1394_join_isoch_cec_error,
2146                     S1394_TNF_SL_ISOCH_ERROR, "", tnf_string, msg,
2147                     "Inconsistent channel mask specified");
2148                 TNF_PROBE_0_DEBUG(t1394_join_isoch_cec_exit,
2149                     S1394_TNF_SL_ISOCH_STACK, "");
2150                 return (DDI_FAILURE);
2151         }
2152 
2153         /* Check for consistent speeds */
2154         if (join_isoch_info->req_max_speed < cec_curr->filter_min_speed) {
2155                 kmem_free(member_new, sizeof (s1394_isoch_cec_member_t));
2156                 /* Unlock the Isoch CEC member list */
2157                 mutex_exit(&cec_curr->isoch_cec_mutex);
2158                 TNF_PROBE_1(t1394_join_isoch_cec_error,
2159                     S1394_TNF_SL_ISOCH_ERROR, "", tnf_string, msg,
2160                     "Inconsistent speed specified");
2161                 TNF_PROBE_0_DEBUG(t1394_join_isoch_cec_exit,
2162                     S1394_TNF_SL_ISOCH_STACK, "");
2163                 return (DDI_FAILURE);
2164         } else if (join_isoch_info->req_max_speed <
2165             cec_curr->filter_current_speed) {
2166                 curr_max_speed = join_isoch_info->req_max_speed;
2167         } else {
2168                 curr_max_speed = cec_curr->filter_current_speed;
2169         }
2170 
2171         /* Check for no more than one talker */
2172         if ((join_isoch_info->jii_options & T1394_TALKER) &&
2173             (cec_curr->cec_member_talker != NULL)) {
2174                 kmem_free(member_new, sizeof (s1394_isoch_cec_member_t));
2175                 /* Unlock the Isoch CEC member list */
2176                 mutex_exit(&cec_curr->isoch_cec_mutex);
2177                 TNF_PROBE_1(t1394_join_isoch_cec_error,
2178                     S1394_TNF_SL_ISOCH_ERROR, "", tnf_string, msg,
2179                     "Multiple talkers specified");
2180                 TNF_PROBE_0_DEBUG(t1394_join_isoch_cec_exit,
2181                     S1394_TNF_SL_ISOCH_STACK, "");
2182                 return (DDI_FAILURE);
2183         }
2184 
2185         /* Verify that all callbacks are non-NULL (for PEER_TO_PEER) */
2186         if ((cec_curr->cec_type == S1394_PEER_TO_PEER) &&
2187             ((join_isoch_info->isoch_cec_evts.setup_target   == NULL) ||
2188             (join_isoch_info->isoch_cec_evts.start_target    == NULL) ||
2189             (join_isoch_info->isoch_cec_evts.stop_target     == NULL) ||
2190             (join_isoch_info->isoch_cec_evts.rsrc_fail_target        == NULL) ||
2191             (join_isoch_info->isoch_cec_evts.teardown_target == NULL))) {
2192                 /* Unlock the Isoch CEC member list */
2193                 mutex_exit(&cec_curr->isoch_cec_mutex);
2194                 TNF_PROBE_1(t1394_join_isoch_cec_error,
2195                     S1394_TNF_SL_ISOCH_ERROR, "", tnf_string, msg,
2196                     "Invalid callbacks specified");
2197                 TNF_PROBE_0_DEBUG(t1394_join_isoch_cec_exit,
2198                     S1394_TNF_SL_ISOCH_STACK, "");
2199                 return (DDI_FAILURE);
2200         }
2201 
2202         /* Copy the events information into the struct */
2203         member_new->isoch_cec_evts   = join_isoch_info->isoch_cec_evts;
2204         member_new->isoch_cec_evts_arg       = join_isoch_info->isoch_cec_evts_arg;
2205         member_new->cec_mem_options  = join_isoch_info->jii_options;
2206         member_new->cec_mem_target   = (s1394_target_t *)t1394_hdl;
2207 
2208         /* Insert new member into Isoch CEC's member list */
2209         s1394_isoch_cec_member_list_insert(hal, cec_curr, member_new);
2210 
2211         /* Update the channel mask filter */
2212         cec_curr->filter_channel_mask        = check_mask;
2213 
2214         /* Update the speed filter */
2215         cec_curr->filter_current_speed       = curr_max_speed;
2216 
2217         /* Update the talker pointer (if necessary) */
2218         if (join_isoch_info->jii_options & T1394_TALKER)
2219                 cec_curr->cec_member_talker = cec_curr->cec_member_list_head;
2220 
2221         /*
2222          * Now "leave" is a legal state transition
2223          * and "free" is an illegal state transition
2224          */
2225         CEC_SET_LEGAL(cec_curr, ISOCH_CEC_LEAVE);
2226         CEC_SET_ILLEGAL(cec_curr, ISOCH_CEC_FREE);
2227 
2228         /* Unlock the Isoch CEC member list */
2229         mutex_exit(&cec_curr->isoch_cec_mutex);
2230 
2231         TNF_PROBE_0_DEBUG(t1394_join_isoch_cec_exit,
2232             S1394_TNF_SL_ISOCH_STACK, "");
2233         return (DDI_SUCCESS);
2234 }
2235 
2236 /*
2237  * Function:    t1394_leave_isoch_cec()
2238  * Input(s):    t1394_hdl               The target "handle" returned by
2239  *                                          t1394_attach()
2240  *              t1394_isoch_cec_hdl     The Isoch CEC "handle" returned by
2241  *                                          t1394_alloc_isoch_cec()
2242  *              flags                   The flags parameter is unused (for now)
2243  *
2244  * Output(s):   DDI_SUCCESS             Target successfully left the
2245  *                                          Isoch CEC
2246  *              DDI_FAILURE             Target failed to leave the Isoch CEC
2247  *
2248  * Description: t1394_leave_isoch_cec() is used by a target driver to remove
2249  *              itself from the Isoch CEC's member list.  It is possible
2250  *              for this call to fail because the target is not found in
2251  *              the current member list, or because it is not an appropriate
2252  *              time for a target to leave.
2253  */
2254 /* ARGSUSED */
2255 int
2256 t1394_leave_isoch_cec(t1394_handle_t t1394_hdl,
2257     t1394_isoch_cec_handle_t t1394_isoch_cec_hdl, uint_t flags)
2258 {
2259         s1394_hal_t              *hal;
2260         s1394_isoch_cec_t        *cec_curr;
2261         s1394_isoch_cec_member_t *member_curr;
2262         s1394_isoch_cec_member_t *member_temp;
2263         boolean_t                found;
2264         uint64_t                 temp_channel_mask;
2265         uint_t                   temp_max_speed;
2266 
2267         TNF_PROBE_0_DEBUG(t1394_leave_isoch_cec_enter,
2268             S1394_TNF_SL_ISOCH_STACK, "");
2269 
2270         ASSERT(t1394_hdl != NULL);
2271         ASSERT(t1394_isoch_cec_hdl != NULL);
2272 
2273         hal = ((s1394_target_t *)t1394_hdl)->on_hal;
2274 
2275         /* Convert the handle to an Isoch CEC pointer */
2276         cec_curr = (s1394_isoch_cec_t *)t1394_isoch_cec_hdl;
2277 
2278         /* Lock the Isoch CEC member list */
2279         mutex_enter(&cec_curr->isoch_cec_mutex);
2280 
2281         /* Are we in any callbacks? (Wait for them to finish) */
2282         while (CEC_IN_ANY_CALLBACKS(cec_curr)) {
2283                 cec_curr->cec_want_wakeup = B_TRUE;
2284                 cv_wait(&cec_curr->in_callbacks_cv,
2285                     &cec_curr->isoch_cec_mutex);
2286         }
2287 
2288         /* Is "leave" a legal state transition? */
2289         if (CEC_TRANSITION_LEGAL(cec_curr, ISOCH_CEC_LEAVE) == 0) {
2290                 /* Unlock the Isoch CEC member list */
2291                 mutex_exit(&cec_curr->isoch_cec_mutex);
2292                 TNF_PROBE_1(t1394_leave_isoch_cec_error,
2293                     S1394_TNF_SL_ISOCH_ERROR, "", tnf_string, msg,
2294                     "Not allowed to leave Isoch CEC");
2295                 TNF_PROBE_0_DEBUG(t1394_leave_isoch_cec_exit,
2296                     S1394_TNF_SL_ISOCH_STACK, "");
2297                 return (DDI_FAILURE);
2298         }
2299 
2300         /* Find the Target on the CEC's member list */
2301         found = B_FALSE;
2302         temp_channel_mask = cec_curr->cec_alloc_props.cec_channel_mask;
2303         temp_max_speed    = cec_curr->cec_alloc_props.cec_max_speed;
2304         member_curr       = cec_curr->cec_member_list_head;
2305         while (member_curr != NULL) {
2306                 if (member_curr->cec_mem_target ==
2307                     (s1394_target_t *)t1394_hdl) {
2308                         member_temp = member_curr;
2309                         found       = B_TRUE;
2310                 } else {
2311                         /* Keep track of channel mask and max speed info */
2312                         temp_channel_mask &= member_curr->req_channel_mask;
2313                         if (member_curr->req_max_speed < temp_max_speed)
2314                                 temp_max_speed = member_curr->req_max_speed;
2315                 }
2316                 member_curr = member_curr->cec_mem_next;
2317         }
2318 
2319         /* Target not found on this Isoch CEC */
2320         if (found == B_FALSE) {
2321                 /* Unlock the Isoch CEC member list */
2322                 mutex_exit(&cec_curr->isoch_cec_mutex);
2323                 TNF_PROBE_1(t1394_leave_isoch_cec_error,
2324                     S1394_TNF_SL_ISOCH_ERROR, "", tnf_string, msg,
2325                     "Target not found in Isoch CEC member list");
2326                 TNF_PROBE_0_DEBUG(t1394_leave_isoch_cec_exit,
2327                     S1394_TNF_SL_ISOCH_STACK, "");
2328                 return (DDI_FAILURE);
2329         } else {
2330                 /* This member's departure may change filter constraints */
2331                 cec_curr->filter_current_speed  = temp_max_speed;
2332                 cec_curr->filter_channel_mask   = temp_channel_mask;
2333         }
2334 
2335         /* Remove member from Isoch CEC's member list */
2336         s1394_isoch_cec_member_list_remove(hal, cec_curr, member_temp);
2337 
2338         /* If we are removing the talker, then update the pointer */
2339         if (cec_curr->cec_member_talker == member_temp)
2340                 cec_curr->cec_member_talker = NULL;
2341 
2342         /* Is the Isoch CEC's member list empty? */
2343         if ((cec_curr->cec_member_list_head == NULL) &&
2344             (cec_curr->cec_member_list_tail == NULL)) {
2345                 /*
2346                  * Now "free" _might_ be a legal state transition
2347                  * if we aren't in setup or start phases and "leave"
2348                  * is definitely an illegal state transition
2349                  */
2350                 if (CEC_TRANSITION_LEGAL(cec_curr, ISOCH_CEC_JOIN) != 0)
2351                         CEC_SET_LEGAL(cec_curr, ISOCH_CEC_FREE);
2352                 CEC_SET_ILLEGAL(cec_curr, ISOCH_CEC_LEAVE);
2353         }
2354 
2355         /* Unlock the Isoch CEC member list */
2356         mutex_exit(&cec_curr->isoch_cec_mutex);
2357 
2358         /* Free the Isoch CEC member structure */
2359         kmem_free(member_temp, sizeof (s1394_isoch_cec_member_t));
2360 
2361         TNF_PROBE_0_DEBUG(t1394_leave_isoch_cec_exit,
2362             S1394_TNF_SL_ISOCH_STACK, "");
2363         return (DDI_SUCCESS);
2364 }
2365 
2366 /*
2367  * Function:    t1394_setup_isoch_cec()
2368  * Input(s):    t1394_hdl               The target "handle" returned by
2369  *                                          t1394_attach()
2370  *              t1394_isoch_cec_hdl     The Isoch CEC "handle" returned by
2371  *                                          t1394_alloc_isoch_cec()
2372  *              flags                   The flags parameter is unused (for now)
2373  *
2374  * Output(s):   result                  Used to pass more specific info back
2375  *                                          to target
2376  *
2377  * Description: t1394_setup_isoch_cec() directs the 1394 Software Framework
2378  *              to allocate isochronous resources and invoke the setup_target()
2379  *              callback for each member of the Isoch CEC.  This call may
2380  *              fail because bandwidth was unavailable (T1394_ENO_BANDWIDTH),
2381  *              channels were unavailable (T1394_ENO_CHANNEL), or one of the
2382  *              member targets returned failure from its setup_target()
2383  *              callback.
2384  */
2385 /* ARGSUSED */
2386 int
2387 t1394_setup_isoch_cec(t1394_handle_t t1394_hdl,
2388     t1394_isoch_cec_handle_t t1394_isoch_cec_hdl, uint_t flags, int *result)
2389 {
2390         s1394_hal_t                     *hal;
2391         s1394_isoch_cec_t               *cec_curr;
2392         s1394_isoch_cec_member_t        *member_curr;
2393         t1394_setup_target_args_t       target_args;
2394         uint64_t                        temp_chnl_mask;
2395         uint32_t                        old_chnl;
2396         uint32_t                        try_chnl;
2397         uint_t                          bw_alloc_units;
2398         uint_t                          generation;
2399         int                             chnl_num;
2400         int                             err;
2401         int                             ret;
2402         int                             j;
2403         int     (*setup_callback)(t1394_isoch_cec_handle_t, opaque_t,
2404                             t1394_setup_target_args_t *);
2405 
2406         TNF_PROBE_0_DEBUG(t1394_setup_isoch_cec_enter,
2407             S1394_TNF_SL_ISOCH_STACK, "");
2408 
2409         ASSERT(t1394_hdl != NULL);
2410         ASSERT(t1394_isoch_cec_hdl != NULL);
2411 
2412         hal = ((s1394_target_t *)t1394_hdl)->on_hal;
2413 
2414         /* Convert the handle to an Isoch CEC pointer */
2415         cec_curr = (s1394_isoch_cec_t *)t1394_isoch_cec_hdl;
2416 
2417         /* Lock the Isoch CEC member list */
2418         mutex_enter(&cec_curr->isoch_cec_mutex);
2419 
2420         /* Are we in any callbacks? */
2421         if (CEC_IN_ANY_CALLBACKS(cec_curr)) {
2422                 /* Unlock the Isoch CEC member list */
2423                 mutex_exit(&cec_curr->isoch_cec_mutex);
2424                 TNF_PROBE_1(t1394_setup_isoch_cec_error,
2425                     S1394_TNF_SL_ISOCH_ERROR, "", tnf_string, msg,
2426                     "Not allowed to setup Isoch CEC (in callbacks)");
2427                 TNF_PROBE_0_DEBUG(t1394_setup_isoch_cec_exit,
2428                     S1394_TNF_SL_ISOCH_STACK, "");
2429                 return (DDI_FAILURE);
2430         }
2431 
2432         /* Is "setup" a legal state transition? */
2433         if (CEC_TRANSITION_LEGAL(cec_curr, ISOCH_CEC_SETUP) == 0) {
2434                 /* Unlock the Isoch CEC member list */
2435                 mutex_exit(&cec_curr->isoch_cec_mutex);
2436                 TNF_PROBE_1(t1394_setup_isoch_cec_error,
2437                     S1394_TNF_SL_ISOCH_ERROR, "", tnf_string, msg,
2438                     "Not allowed to setup Isoch CEC");
2439                 TNF_PROBE_0_DEBUG(t1394_setup_isoch_cec_exit,
2440                     S1394_TNF_SL_ISOCH_STACK, "");
2441                 return (DDI_FAILURE);
2442         }
2443 
2444         /* If T1394_NO_IRM_ALLOC is set then don't allocate... do callbacks */
2445         if (cec_curr->cec_options & T1394_NO_IRM_ALLOC) {
2446                 goto setup_do_callbacks;
2447         }
2448 
2449         /* Allocate bandwidth and channels */
2450         for (j = 0; j < S1394_ISOCH_ALLOC_RETRIES; j++) {
2451                 /*
2452                  * Get the current generation number - don't
2453                  * need the lock because we are read only here
2454                  */
2455                 generation = hal->generation_count;
2456 
2457                 /* Compute how much bandwidth is needed */
2458                 bw_alloc_units = s1394_compute_bw_alloc_units(hal,
2459                     cec_curr->bandwidth, cec_curr->filter_current_speed);
2460 
2461                 /* Check that the generation has not changed - */
2462                 /* don't need the lock (read only) */
2463                 if (generation != hal->generation_count)
2464                         continue;
2465 
2466                 /* Unlock the Isoch CEC member list */
2467                 mutex_exit(&cec_curr->isoch_cec_mutex);
2468 
2469                 /* Try to allocate the bandwidth */
2470                 ret = s1394_bandwidth_alloc(hal, bw_alloc_units, generation,
2471                     &err);
2472 
2473                 /* Lock the Isoch CEC member list */
2474                 mutex_enter(&cec_curr->isoch_cec_mutex);
2475 
2476                 /* If there was a bus reset, start over */
2477                 if (ret == DDI_FAILURE) {
2478                         if (err == CMD1394_EBUSRESET) {
2479                                 continue; /* start over and try again */
2480                         } else {
2481                                 *result = T1394_ENO_BANDWIDTH;
2482                                 /* Unlock the Isoch CEC member list */
2483                                 mutex_exit(&cec_curr->isoch_cec_mutex);
2484                                 TNF_PROBE_1(t1394_setup_isoch_cec_error,
2485                                     S1394_TNF_SL_ISOCH_ERROR, "", tnf_string,
2486                                     msg, "Unable to allocate isoch bandwidth");
2487                                 TNF_PROBE_0_DEBUG(t1394_setup_isoch_cec_exit,
2488                                     S1394_TNF_SL_ISOCH_STACK, "");
2489                                 return (DDI_FAILURE);
2490                         }
2491                 }
2492 
2493                 /* Check that the generation has not changed - */
2494                 /* don't need the lock (read only) */
2495                 if (generation != hal->generation_count)
2496                         continue;
2497 
2498                 /*
2499                  * Allocate a channel
2500                  *    From IEEE 1394-1995, Section 8.3.2.3.8: "Bits
2501                  *    allocated in the CHANNELS_AVAILABLE_HI field of
2502                  *    this register shall start at bit zero (channel
2503                  *    number zero), and additional channel numbers shall
2504                  *    be represented in a monotonically increasing sequence
2505                  *    of bit numbers up to a maximum of bit 31 (channel
2506                  *    number 31).  Bits allocated in the CHANNELS_AVAILABLE_LO
2507                  *    field of this register shall start at bit zero
2508                  *    (channel number 32), and additional channel numbers
2509                  *    shall be represented in a monotonically increasing
2510                  *    sequence of bit numbers up to a maximum of bit 31
2511                  *    (channel number 63).
2512                  */
2513                 temp_chnl_mask = cec_curr->filter_channel_mask;
2514                 for (chnl_num = 63; chnl_num >= 0; chnl_num--) {
2515                         if ((temp_chnl_mask & 1) == 1) {
2516                                 try_chnl = (1 << ((63 - chnl_num) % 32));
2517 
2518                                 /* Unlock the Isoch CEC member list */
2519                                 mutex_exit(&cec_curr->isoch_cec_mutex);
2520                                 if (chnl_num < 32) {
2521                                         ret = s1394_channel_alloc(hal,
2522                                             try_chnl, generation,
2523                                             S1394_CHANNEL_ALLOC_HI, &old_chnl,
2524                                             &err);
2525                                 } else {
2526                                         ret = s1394_channel_alloc(hal,
2527                                             try_chnl, generation,
2528                                             S1394_CHANNEL_ALLOC_LO, &old_chnl,
2529                                             &err);
2530                                 }
2531                                 /* Lock the Isoch CEC member list */
2532                                 mutex_enter(&cec_curr->isoch_cec_mutex);
2533 
2534                                 /* Did we get a channel? (or a bus reset) */
2535                                 if ((ret == DDI_SUCCESS) ||
2536                                     (err == CMD1394_EBUSRESET))
2537                                         break;
2538                         }
2539                         temp_chnl_mask = temp_chnl_mask >> 1;
2540                 }
2541 
2542                 /* If we've tried all the possible channels, then fail */
2543                 if (chnl_num == 0) {
2544                         *result = T1394_ENO_CHANNEL;
2545                         /*
2546                          * If we successfully allocate bandwidth, and
2547                          * then fail getting a channel, we need to
2548                          * free up the bandwidth
2549                          */
2550 
2551                         /* Check that the generation has not changed */
2552                         /* lock not needed here (read only) */
2553                         if (generation != hal->generation_count)
2554                                 continue;
2555 
2556                         /* Unlock the Isoch CEC member list */
2557                         mutex_exit(&cec_curr->isoch_cec_mutex);
2558 
2559                         /* Try to free up the bandwidth */
2560                         ret = s1394_bandwidth_free(hal, bw_alloc_units,
2561                             generation, &err);
2562 
2563                         /* Lock the Isoch CEC member list */
2564                         mutex_enter(&cec_curr->isoch_cec_mutex);
2565 
2566                         if (ret == DDI_FAILURE) {
2567                                 if (err == CMD1394_EBUSRESET) {
2568                                         continue;
2569                                 } else {
2570                                         TNF_PROBE_1(t1394_setup_isoch_cec_error,
2571                                             S1394_TNF_SL_ISOCH_ERROR, "",
2572                                             tnf_string, msg,
2573                                             "Unable to free isoch bandwidth");
2574                                 }
2575                         }
2576 
2577                         /* Unlock the Isoch CEC member list */
2578                         mutex_exit(&cec_curr->isoch_cec_mutex);
2579                         TNF_PROBE_1(t1394_setup_isoch_cec_error,
2580                             S1394_TNF_SL_ISOCH_ERROR, "", tnf_string, msg,
2581                             "Unable to allocate isoch channel");
2582                         TNF_PROBE_0_DEBUG(t1394_setup_isoch_cec_exit,
2583                             S1394_TNF_SL_ISOCH_STACK, "");
2584                         return (DDI_FAILURE);
2585                 }
2586 
2587                 /* If we got a channel, we're done (else start over) */
2588                 if (ret == DDI_SUCCESS)
2589                         break;
2590                 else if (err == CMD1394_EBUSRESET)
2591                         continue;
2592         }
2593 
2594         /* Have we gotten too many bus resets? */
2595         if (j == S1394_ISOCH_ALLOC_RETRIES) {
2596                 *result = T1394_ENO_BANDWIDTH;
2597                 /* Unlock the Isoch CEC member list */
2598                 mutex_exit(&cec_curr->isoch_cec_mutex);
2599                 TNF_PROBE_1(t1394_setup_isoch_cec_error,
2600                     S1394_TNF_SL_ISOCH_ERROR, "", tnf_string, msg,
2601                     "Unable to allocate isoch channel");
2602                 TNF_PROBE_0_DEBUG(t1394_setup_isoch_cec_exit,
2603                     S1394_TNF_SL_ISOCH_STACK, "");
2604                 return (DDI_FAILURE);
2605         }
2606 
2607         cec_curr->realloc_valid          = B_TRUE;
2608         cec_curr->realloc_chnl_num  = chnl_num;
2609         cec_curr->realloc_bandwidth = cec_curr->bandwidth;
2610         cec_curr->realloc_speed          = cec_curr->filter_current_speed;
2611 
2612 setup_do_callbacks:
2613         /* Call all of the setup_target() callbacks */
2614         target_args.channel_num     = chnl_num;
2615         target_args.channel_speed   = cec_curr->filter_current_speed;
2616 
2617         /* Now we are going into the callbacks */
2618         cec_curr->in_callbacks           = B_TRUE;
2619 
2620         /* Unlock the Isoch CEC member list */
2621         mutex_exit(&cec_curr->isoch_cec_mutex);
2622 
2623         member_curr = cec_curr->cec_member_list_head;
2624         *result = 0;
2625         while (member_curr != NULL) {
2626                 if (member_curr->isoch_cec_evts.setup_target != NULL) {
2627                         setup_callback =
2628                             member_curr->isoch_cec_evts.setup_target;
2629                         ret = setup_callback(t1394_isoch_cec_hdl,
2630                             member_curr->isoch_cec_evts_arg, &target_args);
2631                         if (ret != DDI_SUCCESS)
2632                                 *result = T1394_ETARGET;
2633                 }
2634                 member_curr = member_curr->cec_mem_next;
2635         }
2636 
2637         /* Lock the Isoch CEC member list */
2638         mutex_enter(&cec_curr->isoch_cec_mutex);
2639 
2640         /* We are finished with the callbacks */
2641         cec_curr->in_callbacks = B_FALSE;
2642         if (cec_curr->cec_want_wakeup == B_TRUE) {
2643                 cec_curr->cec_want_wakeup = B_FALSE;
2644                 cv_broadcast(&cec_curr->in_callbacks_cv);
2645         }
2646 
2647         /*
2648          * Now "start" and "teardown" are legal state transitions
2649          * and "join", "free", and "setup" are illegal state transitions
2650          */
2651         CEC_SET_LEGAL(cec_curr, (ISOCH_CEC_START | ISOCH_CEC_TEARDOWN));
2652         CEC_SET_ILLEGAL(cec_curr, (ISOCH_CEC_JOIN | ISOCH_CEC_FREE |
2653             ISOCH_CEC_SETUP));
2654 
2655         /* Unlock the Isoch CEC member list */
2656         mutex_exit(&cec_curr->isoch_cec_mutex);
2657 
2658         /* Return DDI_FAILURE if any targets failed setup */
2659         if (*result != 0) {
2660                 TNF_PROBE_1(t1394_setup_isoch_cec_error,
2661                     S1394_TNF_SL_ISOCH_ERROR, "", tnf_string, msg,
2662                     "Target returned error in setup_target()");
2663                 TNF_PROBE_0_DEBUG(t1394_setup_isoch_cec_exit,
2664                     S1394_TNF_SL_ISOCH_STACK, "");
2665                 return (DDI_FAILURE);
2666         }
2667 
2668         TNF_PROBE_0_DEBUG(t1394_setup_isoch_cec_exit,
2669             S1394_TNF_SL_ISOCH_STACK, "");
2670         return (DDI_SUCCESS);
2671 }
2672 
2673 /*
2674  * Function:    t1394_start_isoch_cec()
2675  * Input(s):    t1394_hdl               The target "handle" returned by
2676  *                                          t1394_attach()
2677  *              t1394_isoch_cec_hdl     The Isoch CEC "handle" returned by
2678  *                                          t1394_alloc_isoch_cec()
2679  *              flags                   The flags parameter is unused (for now)
2680  *
2681  * Output(s):   DDI_SUCCESS             All start_target() callbacks returned
2682  *                                          successfully
2683  *              DDI_FAILURE             One or more start_target() callbacks
2684  *                                          returned failure
2685  *
2686  * Description: t1394_start_isoch_cec() directs the 1394 Software Framework
2687  *              to invoke each of the start_target() callbacks, first for
2688  *              each listener, then for the talker.
2689  */
2690 /* ARGSUSED */
2691 int
2692 t1394_start_isoch_cec(t1394_handle_t t1394_hdl,
2693     t1394_isoch_cec_handle_t t1394_isoch_cec_hdl, uint_t flags)
2694 {
2695         s1394_isoch_cec_t        *cec_curr;
2696         s1394_isoch_cec_member_t *member_curr;
2697         int                      ret;
2698         boolean_t                err;
2699         int     (*start_callback)(t1394_isoch_cec_handle_t, opaque_t);
2700 
2701         TNF_PROBE_0_DEBUG(t1394_start_isoch_cec_enter,
2702             S1394_TNF_SL_ISOCH_STACK, "");
2703 
2704         ASSERT(t1394_hdl != NULL);
2705         ASSERT(t1394_isoch_cec_hdl != NULL);
2706 
2707         /* Convert the handle to an Isoch CEC pointer */
2708         cec_curr = (s1394_isoch_cec_t *)t1394_isoch_cec_hdl;
2709 
2710         /* Lock the Isoch CEC member list */
2711         mutex_enter(&cec_curr->isoch_cec_mutex);
2712 
2713         /* Are we in any callbacks? */
2714         if (CEC_IN_ANY_CALLBACKS(cec_curr)) {
2715                 /* Unlock the Isoch CEC member list */
2716                 mutex_exit(&cec_curr->isoch_cec_mutex);
2717                 TNF_PROBE_1(t1394_start_isoch_cec_error,
2718                     S1394_TNF_SL_ISOCH_ERROR, "", tnf_string, msg,
2719                     "Not allowed to start Isoch CEC (in callbacks)");
2720                 TNF_PROBE_0_DEBUG(t1394_start_isoch_cec_exit,
2721                     S1394_TNF_SL_ISOCH_STACK, "");
2722                 return (DDI_FAILURE);
2723         }
2724 
2725         /* Is "start" a legal state transition? */
2726         if (CEC_TRANSITION_LEGAL(cec_curr, ISOCH_CEC_START) == 0) {
2727                 /* Unlock the Isoch CEC member list */
2728                 mutex_exit(&cec_curr->isoch_cec_mutex);
2729                 TNF_PROBE_1(t1394_start_isoch_cec_error,
2730                     S1394_TNF_SL_ISOCH_ERROR, "", tnf_string, msg,
2731                     "Not allowed to start Isoch CEC");
2732                 TNF_PROBE_0_DEBUG(t1394_start_isoch_cec_exit,
2733                     S1394_TNF_SL_ISOCH_STACK, "");
2734                 return (DDI_FAILURE);
2735         }
2736 
2737         /* Now we are going into the callbacks */
2738         cec_curr->in_callbacks = B_TRUE;
2739 
2740         /* Unlock the Isoch CEC member list */
2741         mutex_exit(&cec_curr->isoch_cec_mutex);
2742 
2743         /*
2744          * Call all of the start_target() callbacks
2745          * Start at the tail (listeners first) and
2746          * go toward the head (talker last)
2747          */
2748         member_curr = cec_curr->cec_member_list_tail;
2749         err = B_FALSE;
2750         while (member_curr != NULL) {
2751                 if (member_curr->isoch_cec_evts.start_target != NULL) {
2752                         start_callback =
2753                             member_curr->isoch_cec_evts.start_target;
2754                         ret = start_callback(t1394_isoch_cec_hdl,
2755                             member_curr->isoch_cec_evts_arg);
2756                 if (ret != DDI_SUCCESS)
2757                         err = B_TRUE;
2758                 }
2759                 member_curr = member_curr->cec_mem_prev;
2760         }
2761 
2762         /* Lock the Isoch CEC member list */
2763         mutex_enter(&cec_curr->isoch_cec_mutex);
2764 
2765         /* We are finished with the callbacks */
2766         cec_curr->in_callbacks = B_FALSE;
2767         if (cec_curr->cec_want_wakeup == B_TRUE) {
2768                 cec_curr->cec_want_wakeup = B_FALSE;
2769                 cv_broadcast(&cec_curr->in_callbacks_cv);
2770         }
2771 
2772         /*
2773          * Now "stop" is a legal state transitions
2774          * and "start" and "teardown" are illegal state transitions
2775          */
2776         CEC_SET_LEGAL(cec_curr, ISOCH_CEC_STOP);
2777         CEC_SET_ILLEGAL(cec_curr, (ISOCH_CEC_START | ISOCH_CEC_TEARDOWN));
2778 
2779         /* Unlock the Isoch CEC member list */
2780         mutex_exit(&cec_curr->isoch_cec_mutex);
2781 
2782         /* Return DDI_FAILURE if any targets failed start */
2783         if (err == B_TRUE) {
2784                 TNF_PROBE_1(t1394_start_isoch_cec_error,
2785                     S1394_TNF_SL_ISOCH_ERROR, "", tnf_string, msg,
2786                     "Target returned error in start_target()");
2787                 TNF_PROBE_0_DEBUG(t1394_start_isoch_cec_exit,
2788                     S1394_TNF_SL_ISOCH_STACK, "");
2789                 return (DDI_FAILURE);
2790         }
2791 
2792         TNF_PROBE_0_DEBUG(t1394_start_isoch_cec_exit,
2793                     S1394_TNF_SL_ISOCH_STACK, "");
2794         return (DDI_SUCCESS);
2795 }
2796 
2797 /*
2798  * Function:    t1394_stop_isoch_cec()
2799  * Input(s):    t1394_hdl               The target "handle" returned by
2800  *                                          t1394_attach()
2801  *              t1394_isoch_cec_hdl     The Isoch CEC "handle" returned by
2802  *                                          t1394_alloc_isoch_cec()
2803  *              flags                   The flags parameter is unused (for now)
2804  *
2805  * Output(s):   DDI_SUCCESS             Target successfully stopped the
2806  *                                          Isoch CEC
2807  *              DDI_FAILURE             Target failed to stop the Isoch CEC
2808  *
2809  * Description: t1394_stop_isoch_cec() directs the 1394 Software Framework
2810  *              to invoke each of the stop_target() callbacks, first for
2811  *              the talker, then for each listener.
2812  *              (This call will fail if it is called at an
2813  *              inappropriate time, i.e. before the t1394_start_isoch_cec()
2814  *              call, etc.)
2815  */
2816 /* ARGSUSED */
2817 int
2818 t1394_stop_isoch_cec(t1394_handle_t t1394_hdl,
2819     t1394_isoch_cec_handle_t t1394_isoch_cec_hdl, uint_t flags)
2820 {
2821         s1394_isoch_cec_t        *cec_curr;
2822         s1394_isoch_cec_member_t *member_curr;
2823         void    (*stop_callback)(t1394_isoch_cec_handle_t, opaque_t);
2824 
2825         TNF_PROBE_0_DEBUG(t1394_stop_isoch_cec_enter,
2826             S1394_TNF_SL_ISOCH_STACK, "");
2827 
2828         ASSERT(t1394_hdl != NULL);
2829         ASSERT(t1394_isoch_cec_hdl != NULL);
2830 
2831         /* Convert the handle to an Isoch CEC pointer */
2832         cec_curr = (s1394_isoch_cec_t *)t1394_isoch_cec_hdl;
2833 
2834         /* Lock the Isoch CEC member list */
2835         mutex_enter(&cec_curr->isoch_cec_mutex);
2836 
2837         /* Are we in any callbacks? */
2838         if (CEC_IN_ANY_CALLBACKS(cec_curr)) {
2839                 /* Unlock the Isoch CEC member list */
2840                 mutex_exit(&cec_curr->isoch_cec_mutex);
2841                 TNF_PROBE_1(t1394_stop_isoch_cec_error,
2842                     S1394_TNF_SL_ISOCH_ERROR, "", tnf_string, msg,
2843                     "Not allowed to stop Isoch CEC (in callbacks)");
2844                 TNF_PROBE_0_DEBUG(t1394_stop_isoch_cec_exit,
2845                     S1394_TNF_SL_ISOCH_STACK, "");
2846                 return (DDI_FAILURE);
2847         }
2848 
2849         /* Is "stop" a legal state transition? */
2850         if (CEC_TRANSITION_LEGAL(cec_curr, ISOCH_CEC_STOP) == 0) {
2851                 /* Unlock the Isoch CEC member list */
2852                 mutex_exit(&cec_curr->isoch_cec_mutex);
2853                 TNF_PROBE_1(t1394_stop_isoch_cec_error,
2854                     S1394_TNF_SL_ISOCH_ERROR, "", tnf_string, msg,
2855                     "Not allowed to stop Isoch CEC");
2856                 TNF_PROBE_0_DEBUG(t1394_stop_isoch_cec_exit,
2857                     S1394_TNF_SL_ISOCH_STACK, "");
2858                 return (DDI_FAILURE);
2859         }
2860 
2861         /* Now we are going into the callbacks */
2862         cec_curr->in_callbacks = B_TRUE;
2863 
2864         /* Unlock the Isoch CEC member list */
2865         mutex_exit(&cec_curr->isoch_cec_mutex);
2866 
2867         /*
2868          * Call all of the stop_target() callbacks
2869          * Start at the head (talker first) and
2870          * go toward the tail (listeners last)
2871          */
2872         member_curr = cec_curr->cec_member_list_head;
2873         while (member_curr != NULL) {
2874                 if (member_curr->isoch_cec_evts.stop_target != NULL) {
2875                         stop_callback =
2876                             member_curr->isoch_cec_evts.stop_target;
2877                         stop_callback(t1394_isoch_cec_hdl,
2878                             member_curr->isoch_cec_evts_arg);
2879                 }
2880                 member_curr = member_curr->cec_mem_next;
2881         }
2882 
2883         /* Lock the Isoch CEC member list */
2884         mutex_enter(&cec_curr->isoch_cec_mutex);
2885 
2886         /* We are finished with the callbacks */
2887         cec_curr->in_callbacks = B_FALSE;
2888         if (cec_curr->cec_want_wakeup == B_TRUE) {
2889                 cec_curr->cec_want_wakeup = B_FALSE;
2890                 cv_broadcast(&cec_curr->in_callbacks_cv);
2891         }
2892 
2893         /*
2894          * Now "start" and "teardown" are legal state transitions
2895          * and "stop" is an illegal state transitions
2896          */
2897         CEC_SET_LEGAL(cec_curr, (ISOCH_CEC_START | ISOCH_CEC_TEARDOWN));
2898         CEC_SET_ILLEGAL(cec_curr, ISOCH_CEC_STOP);
2899 
2900         /* Unlock the Isoch CEC member list */
2901         mutex_exit(&cec_curr->isoch_cec_mutex);
2902 
2903         TNF_PROBE_0_DEBUG(t1394_stop_isoch_cec_exit,
2904             S1394_TNF_SL_ISOCH_STACK, "");
2905         return (DDI_SUCCESS);
2906 }
2907 
2908 /*
2909  * Function:    t1394_teardown_isoch_cec()
2910  * Input(s):    t1394_hdl               The target "handle" returned by
2911  *                                          t1394_attach()
2912  *              t1394_isoch_cec_hdl     The Isoch CEC "handle" returned by
2913  *                                          t1394_alloc_isoch_cec()
2914  *              flags                   The flags parameter is unused (for now)
2915  *
2916  * Output(s):   DDI_SUCCESS             Target successfully tore down the
2917  *                                          Isoch CEC
2918  *              DDI_FAILURE             Target failed to tear down the
2919  *                                          Isoch CEC
2920  *
2921  * Description: t1394_teardown_isoch_cec() directs the 1394 Software Framework
2922  *              to free up any isochronous resources we might be holding and
2923  *              call all of the teardown_target() callbacks.
2924  *              (This call will fail if it is called at an
2925  *              inappropriate time, i.e. before the t1394_start_isoch_cec()
2926  *              call, before the t1394_stop_isoch_cec, etc.
2927  */
2928 /* ARGSUSED */
2929 int
2930 t1394_teardown_isoch_cec(t1394_handle_t t1394_hdl,
2931     t1394_isoch_cec_handle_t t1394_isoch_cec_hdl, uint_t flags)
2932 {
2933         s1394_hal_t              *hal;
2934         s1394_isoch_cec_t        *cec_curr;
2935         s1394_isoch_cec_member_t *member_curr;
2936         uint32_t                 chnl_mask;
2937         uint32_t                 old_chnl_mask;
2938         uint_t                   bw_alloc_units;
2939         uint_t                   generation;
2940         int                      ret;
2941         int                      err;
2942         void    (*teardown_callback)(t1394_isoch_cec_handle_t, opaque_t);
2943 
2944         TNF_PROBE_0_DEBUG(t1394_teardown_isoch_cec_enter,
2945             S1394_TNF_SL_ISOCH_STACK, "");
2946 
2947         ASSERT(t1394_hdl != NULL);
2948         ASSERT(t1394_isoch_cec_hdl != NULL);
2949 
2950         hal = ((s1394_target_t *)t1394_hdl)->on_hal;
2951 
2952         /* Convert the handle to an Isoch CEC pointer */
2953         cec_curr = (s1394_isoch_cec_t *)t1394_isoch_cec_hdl;
2954 
2955         /* Lock the Isoch CEC member list */
2956         mutex_enter(&cec_curr->isoch_cec_mutex);
2957 
2958         /* Are we in any callbacks? */
2959         if (CEC_IN_ANY_CALLBACKS(cec_curr)) {
2960                 /* Unlock the Isoch CEC member list */
2961                 mutex_exit(&cec_curr->isoch_cec_mutex);
2962                 TNF_PROBE_1(t1394_teardown_isoch_cec_error,
2963                     S1394_TNF_SL_ISOCH_ERROR, "", tnf_string, msg,
2964                     "Not allowed to teardown Isoch CEC (in callbacks)");
2965                 TNF_PROBE_0_DEBUG(t1394_teardown_isoch_cec_exit,
2966                     S1394_TNF_SL_ISOCH_STACK, "");
2967                 return (DDI_FAILURE);
2968         }
2969 
2970         /* Is "teardown" a legal state transition? */
2971         if (CEC_TRANSITION_LEGAL(cec_curr, ISOCH_CEC_TEARDOWN) == 0) {
2972                 /* Unlock the Isoch CEC member list */
2973                 mutex_exit(&cec_curr->isoch_cec_mutex);
2974                 TNF_PROBE_1(t1394_teardown_isoch_cec_error,
2975                     S1394_TNF_SL_ISOCH_ERROR, "", tnf_string, msg,
2976                     "Not allowed to teardown Isoch CEC");
2977                 TNF_PROBE_0_DEBUG(t1394_teardown_isoch_cec_exit,
2978                     S1394_TNF_SL_ISOCH_STACK, "");
2979                 return (DDI_FAILURE);
2980         }
2981 
2982         /* If T1394_NO_IRM_ALLOC is set then don't free... do callbacks */
2983         if (cec_curr->cec_options & T1394_NO_IRM_ALLOC) {
2984                 goto teardown_do_callbacks;
2985         }
2986 
2987         /* If nothing has been allocated or we failed to */
2988         /* reallocate, then we are done... call the callbacks */
2989         if ((cec_curr->realloc_valid == B_FALSE) ||
2990             (cec_curr->realloc_failed == B_TRUE)) {
2991                 goto teardown_do_callbacks;
2992         }
2993 
2994         /*
2995          * Get the current generation number - don't need the
2996          * topology tree mutex here because it is read-only, and
2997          * there is a race condition with or without it.
2998          */
2999         generation = hal->generation_count;
3000 
3001         /* Compute the amount bandwidth to free */
3002         bw_alloc_units = s1394_compute_bw_alloc_units(hal,
3003             cec_curr->bandwidth, cec_curr->realloc_speed);
3004 
3005         /* Check that the generation has not changed - */
3006         /* don't need the lock (read only) */
3007         if (generation != hal->generation_count)
3008                 goto teardown_do_callbacks;
3009 
3010         /* Unlock the Isoch CEC member list */
3011         mutex_exit(&cec_curr->isoch_cec_mutex);
3012 
3013         /* Try to free up the bandwidth */
3014         ret = s1394_bandwidth_free(hal, bw_alloc_units, generation, &err);
3015 
3016         /* Lock the Isoch CEC member list */
3017         mutex_enter(&cec_curr->isoch_cec_mutex);
3018 
3019         if (ret == DDI_FAILURE) {
3020                 if (err == CMD1394_EBUSRESET) {
3021                         goto teardown_do_callbacks;
3022                 } else {
3023                         TNF_PROBE_1(t1394_teardown_isoch_cec_error,
3024                             S1394_TNF_SL_ISOCH_ERROR, "", tnf_string, msg,
3025                             "Unable to free allocated bandwidth");
3026                 }
3027         }
3028 
3029         /* Free the allocated channel */
3030         chnl_mask = (1 << ((63 - cec_curr->realloc_chnl_num) % 32));
3031 
3032         /* Unlock the Isoch CEC member list */
3033         mutex_exit(&cec_curr->isoch_cec_mutex);
3034         if (cec_curr->realloc_chnl_num < 32) {
3035                 ret = s1394_channel_free(hal, chnl_mask, generation,
3036                     S1394_CHANNEL_ALLOC_HI, &old_chnl_mask, &err);
3037         } else {
3038                 ret = s1394_channel_free(hal, chnl_mask, generation,
3039                     S1394_CHANNEL_ALLOC_LO, &old_chnl_mask, &err);
3040         }
3041         /* Lock the Isoch CEC member list */
3042         mutex_enter(&cec_curr->isoch_cec_mutex);
3043 
3044         if (ret == DDI_FAILURE) {
3045                 if (err == CMD1394_EBUSRESET) {
3046                         goto teardown_do_callbacks;
3047                 } else {
3048                         TNF_PROBE_1(t1394_teardown_isoch_cec_error,
3049                             S1394_TNF_SL_ISOCH_ERROR, "", tnf_string, msg,
3050                             "Unable to free allocated bandwidth");
3051                 }
3052         }
3053 
3054 teardown_do_callbacks:
3055         /* From here on reallocation is unnecessary */
3056         cec_curr->realloc_valid          = B_FALSE;
3057         cec_curr->realloc_chnl_num  = 0;
3058         cec_curr->realloc_bandwidth = 0;
3059 
3060         /* Now we are going into the callbacks */
3061         cec_curr->in_callbacks           = B_TRUE;
3062 
3063         /* Unlock the Isoch CEC member list */
3064         mutex_exit(&cec_curr->isoch_cec_mutex);
3065 
3066         /* Call all of the teardown_target() callbacks */
3067         member_curr = cec_curr->cec_member_list_head;
3068         while (member_curr != NULL) {
3069                 if (member_curr->isoch_cec_evts.teardown_target != NULL) {
3070                         teardown_callback =
3071                             member_curr->isoch_cec_evts.teardown_target;
3072                         teardown_callback(t1394_isoch_cec_hdl,
3073                             member_curr->isoch_cec_evts_arg);
3074                 }
3075                 member_curr = member_curr->cec_mem_next;
3076         }
3077 
3078         /* Lock the Isoch CEC member list */
3079         mutex_enter(&cec_curr->isoch_cec_mutex);
3080 
3081         /* We are finished with the callbacks */
3082         cec_curr->in_callbacks = B_FALSE;
3083         if (cec_curr->cec_want_wakeup == B_TRUE) {
3084                 cec_curr->cec_want_wakeup = B_FALSE;
3085                 cv_broadcast(&cec_curr->in_callbacks_cv);
3086         }
3087 
3088         /*
3089          * Now "join" and "setup" are legal state transitions
3090          * and "start" and "teardown" are illegal state transitions
3091          */
3092         CEC_SET_LEGAL(cec_curr, (ISOCH_CEC_JOIN | ISOCH_CEC_SETUP));
3093         CEC_SET_ILLEGAL(cec_curr, (ISOCH_CEC_START | ISOCH_CEC_TEARDOWN));
3094 
3095         /* And if the member list is empty, then "free" is legal too */
3096         if ((cec_curr->cec_member_list_head == NULL) &&
3097             (cec_curr->cec_member_list_tail == NULL)) {
3098                 CEC_SET_LEGAL(cec_curr, ISOCH_CEC_FREE);
3099         }
3100 
3101         /* Unlock the Isoch CEC member list */
3102         mutex_exit(&cec_curr->isoch_cec_mutex);
3103         TNF_PROBE_0_DEBUG(t1394_teardown_isoch_cec_exit,
3104             S1394_TNF_SL_ISOCH_STACK, "");
3105         return (DDI_SUCCESS);
3106 }
3107 
3108 /*
3109  * Function:    t1394_alloc_isoch_dma()
3110  * Input(s):    t1394_hdl               The target "handle" returned by
3111  *                                          t1394_attach()
3112  *              idi                     This structure contains information
3113  *                                          for configuring the data flow for
3114  *                                          isochronous DMA
3115  *              flags                   The flags parameter is unused (for now)
3116  *
3117  * Output(s):   t1394_idma_hdl          The IDMA "handle" used in all
3118  *                                          subsequent isoch_dma() calls
3119  *              result                  Used to pass more specific info back
3120  *                                          to target
3121  *
3122  * Description: t1394_alloc_isoch_dma() allocates and initializes an
3123  *              isochronous DMA resource for transmitting or receiving
3124  *              isochronous data.  If it fails, result may hold
3125  *              T1394_EIDMA_NO_RESRCS, indicating that no isoch DMA resource
3126  *              are available.
3127  */
3128 /* ARGSUSED */
3129 int
3130 t1394_alloc_isoch_dma(t1394_handle_t t1394_hdl,
3131     id1394_isoch_dmainfo_t *idi, uint_t flags,
3132     t1394_isoch_dma_handle_t *t1394_idma_hdl, int *result)
3133 {
3134         s1394_hal_t     *hal;
3135         int             ret;
3136 
3137         TNF_PROBE_0_DEBUG(t1394_alloc_isoch_dma_enter,
3138             S1394_TNF_SL_ISOCH_STACK, "");
3139 
3140         ASSERT(t1394_hdl != NULL);
3141         ASSERT(idi != NULL);
3142         ASSERT(t1394_idma_hdl != NULL);
3143 
3144         /* Find the HAL this target resides on */
3145         hal = ((s1394_target_t *)t1394_hdl)->on_hal;
3146 
3147         /* Sanity check dma options.  If talk enabled, listen should be off */
3148         if ((idi->idma_options & ID1394_TALK) &&
3149             (idi->idma_options != ID1394_TALK)) {
3150                 TNF_PROBE_1(t1394_alloc_isoch_dma_talk_conflict_error,
3151                     S1394_TNF_SL_ISOCH_ERROR, "", tnf_string, msg,
3152                     "conflicting idma options; talker and listener");
3153                 TNF_PROBE_0_DEBUG(t1394_alloc_isoch_dma_exit,
3154                     S1394_TNF_SL_ISOCH_STACK, "");
3155 
3156                 *result = T1394_EIDMA_CONFLICT;
3157                 return (DDI_FAILURE);
3158         }
3159 
3160         /* Only one listen mode allowed */
3161         if ((idi->idma_options & ID1394_LISTEN_PKT_MODE) &&
3162             (idi->idma_options & ID1394_LISTEN_BUF_MODE)) {
3163                 TNF_PROBE_1(t1394_alloc_isoch_dma_listen_conflict_error,
3164                     S1394_TNF_SL_ISOCH_ERROR, "", tnf_string, msg,
3165                     "conflicting idma options; both listener modes set");
3166                 TNF_PROBE_0_DEBUG(t1394_alloc_isoch_dma_exit,
3167                     S1394_TNF_SL_ISOCH_STACK, "");
3168 
3169                 *result = T1394_EIDMA_CONFLICT;
3170                 return (DDI_FAILURE);
3171         }
3172 
3173         /* Have HAL alloc a resource and compile ixl */
3174         ret = HAL_CALL(hal).alloc_isoch_dma(hal->halinfo.hal_private, idi,
3175             (void **)t1394_idma_hdl, result);
3176 
3177         if (ret != DDI_SUCCESS) {
3178                 TNF_PROBE_1(t1394_alloc_isoch_dma_hal_error,
3179                     S1394_TNF_SL_ISOCH_ERROR, "", tnf_string, msg,
3180                     "HAL alloc_isoch_dma error, maybe IXL compilation");
3181                 if (*result == IXL1394_ENO_DMA_RESRCS) {
3182                         *result = T1394_EIDMA_NO_RESRCS;
3183                 }
3184         }
3185 
3186         TNF_PROBE_0_DEBUG(t1394_alloc_isoch_dma_exit,
3187             S1394_TNF_SL_ISOCH_STACK, "");
3188         return (ret);
3189 }
3190 
3191 /*
3192  * Function:    t1394_free_isoch_dma()
3193  * Input(s):    t1394_hdl               The target "handle" returned by
3194  *                                          t1394_attach()
3195  *              flags                   The flags parameter is unused (for now)
3196  *              t1394_idma_hdl          The IDMA "handle" returned by
3197  *                                          t1394_alloc_isoch_dma()
3198  *
3199  * Output(s):   None
3200  *
3201  * Description: t1394_free_isoch_dma() is used to free all DMA resources
3202  *              allocated for the isoch stream associated with t1394_idma_hdl.
3203  */
3204 /* ARGSUSED */
3205 void
3206 t1394_free_isoch_dma(t1394_handle_t t1394_hdl, uint_t flags,
3207     t1394_isoch_dma_handle_t *t1394_idma_hdl)
3208 {
3209         s1394_hal_t     *hal;
3210 
3211         TNF_PROBE_0_DEBUG(t1394_free_isoch_dma_enter,
3212             S1394_TNF_SL_ISOCH_STACK, "");
3213 
3214         ASSERT(t1394_hdl != NULL);
3215         ASSERT(*t1394_idma_hdl != NULL);
3216 
3217         /* Find the HAL this target resides on */
3218         hal = ((s1394_target_t *)t1394_hdl)->on_hal;
3219 
3220         /* Tell HAL to release local isoch dma resources */
3221         HAL_CALL(hal).free_isoch_dma(hal->halinfo.hal_private, *t1394_idma_hdl);
3222 
3223         /* Null out isoch handle */
3224         *t1394_idma_hdl = NULL;
3225 
3226         TNF_PROBE_0_DEBUG(t1394_free_isoch_dma_exit,
3227             S1394_TNF_SL_ISOCH_STACK, "");
3228 }
3229 
3230 /*
3231  * Function:    t1394_start_isoch_dma()
3232  * Input(s):    t1394_hdl               The target "handle" returned by
3233  *                                          t1394_attach()
3234  *              t1394_idma_hdl          The IDMA "handle" returned by
3235  *                                          t1394_alloc_isoch_dma()
3236  *              idma_ctrlinfo           This structure contains control args
3237  *                                          used when starting isoch DMA for
3238  *                                          the allocated resource
3239  *              flags                   One flag defined - ID1394_START_ON_CYCLE
3240  *
3241  * Output(s):   result                  Used to pass more specific info back
3242  *                                          to target
3243  *
3244  * Description: t1394_start_isoch_dma() is used to start DMA for the isoch
3245  *              stream associated with t1394_idma_hdl.
3246  */
3247 /* ARGSUSED */
3248 int
3249 t1394_start_isoch_dma(t1394_handle_t t1394_hdl,
3250     t1394_isoch_dma_handle_t t1394_idma_hdl,
3251     id1394_isoch_dma_ctrlinfo_t *idma_ctrlinfo, uint_t flags,
3252     int *result)
3253 {
3254         s1394_hal_t     *hal;
3255         int             ret;
3256 
3257         TNF_PROBE_0_DEBUG(t1394_start_isoch_dma_enter,
3258             S1394_TNF_SL_ISOCH_STACK, "");
3259 
3260         ASSERT(t1394_hdl != NULL);
3261         ASSERT(t1394_idma_hdl != NULL);
3262         ASSERT(idma_ctrlinfo != NULL);
3263 
3264         /* Find the HAL this target resides on */
3265         hal = ((s1394_target_t *)t1394_hdl)->on_hal;
3266 
3267         ret = HAL_CALL(hal).start_isoch_dma(hal->halinfo.hal_private,
3268             (void *)t1394_idma_hdl, idma_ctrlinfo, flags, result);
3269 
3270         TNF_PROBE_0_DEBUG(t1394_start_isoch_dma_exit,
3271             S1394_TNF_SL_ISOCH_STACK, "");
3272         return (ret);
3273 }
3274 
3275 /*
3276  * Function:    t1394_stop_isoch_dma()
3277  * Input(s):    t1394_hdl               The target "handle" returned by
3278  *                                          t1394_attach()
3279  *              t1394_idma_hdl          The IDMA "handle" returned by
3280  *                                          t1394_alloc_isoch_dma()
3281  *              flags                   The flags parameter is unused (for now)
3282  *
3283  * Output(s):   None
3284  *
3285  * Description: t1394_stop_isoch_dma() is used to stop DMA for the isoch
3286  *              stream associated with t1394_idma_hdl.
3287  */
3288 /* ARGSUSED */
3289 void
3290 t1394_stop_isoch_dma(t1394_handle_t t1394_hdl,
3291     t1394_isoch_dma_handle_t t1394_idma_hdl, uint_t flags)
3292 {
3293         s1394_hal_t     *hal;
3294         int             result;
3295 
3296         TNF_PROBE_0_DEBUG(t1394_stop_isoch_dma_enter,
3297             S1394_TNF_SL_ISOCH_STACK, "");
3298 
3299         ASSERT(t1394_hdl != NULL);
3300         ASSERT(t1394_idma_hdl != NULL);
3301 
3302         /* Find the HAL this target resides on */
3303         hal = ((s1394_target_t *)t1394_hdl)->on_hal;
3304 
3305         HAL_CALL(hal).stop_isoch_dma(hal->halinfo.hal_private,
3306             (void *)t1394_idma_hdl, &result);
3307 
3308         TNF_PROBE_0_DEBUG(t1394_stop_isoch_dma_exit,
3309             S1394_TNF_SL_ISOCH_STACK, "");
3310 }
3311 
3312 /*
3313  * Function:    t1394_update_isoch_dma()
3314  * Input(s):    t1394_hdl               The target "handle" returned by
3315  *                                          t1394_attach()
3316  *              t1394_idma_hdl          The IDMA "handle" returned by
3317  *                                          t1394_alloc_isoch_dma()
3318  *              idma_updateinfo         This structure contains ixl command args
3319  *                                          used when updating args in an
3320  *                                          existing list of ixl commands with
3321  *                                          args in a new list of ixl commands.
3322  *              flags                   The flags parameter is unused (for now)
3323  *
3324  * Output(s):   result                  Used to pass more specific info back
3325  *                                          to target
3326  *
3327  * Description: t1394_update_isoch_dma() is used to alter an IXL program that
3328  *              has already been built (compiled) by t1394_alloc_isoch_dma().
3329  */
3330 /* ARGSUSED */
3331 int
3332 t1394_update_isoch_dma(t1394_handle_t t1394_hdl,
3333     t1394_isoch_dma_handle_t t1394_idma_hdl,
3334     id1394_isoch_dma_updateinfo_t *idma_updateinfo, uint_t flags,
3335     int *result)
3336 {
3337         s1394_hal_t     *hal;
3338         int             ret;
3339 
3340         TNF_PROBE_0_DEBUG(t1394_update_isoch_dma_enter,
3341             S1394_TNF_SL_ISOCH_STACK, "");
3342 
3343         ASSERT(t1394_hdl != NULL);
3344         ASSERT(t1394_idma_hdl != NULL);
3345         ASSERT(idma_updateinfo != NULL);
3346 
3347         /* Find the HAL this target resides on */
3348         hal = ((s1394_target_t *)t1394_hdl)->on_hal;
3349 
3350         ret = HAL_CALL(hal).update_isoch_dma(hal->halinfo.hal_private,
3351             (void *)t1394_idma_hdl, idma_updateinfo, flags, result);
3352 
3353         TNF_PROBE_0_DEBUG(t1394_update_isoch_dma_exit,
3354             S1394_TNF_SL_ISOCH_STACK, "");
3355         return (ret);
3356 }
3357 
3358 /*
3359  * Function:    t1394_initiate_bus_reset()
3360  * Input(s):    t1394_hdl               The target "handle" returned by
3361  *                                          t1394_attach()
3362  *              flags                   The flags parameter is unused (for now)
3363  *
3364  * Output(s):   None
3365  *
3366  * Description: t1394_initiate_bus_reset() determines whether the local
3367  *              device has a P1394A PHY and will support the arbitrated
3368  *              short bus reset. If not, it will initiate a normal bus reset.
3369  */
3370 /* ARGSUSED */
3371 void
3372 t1394_initiate_bus_reset(t1394_handle_t t1394_hdl, uint_t flags)
3373 {
3374         s1394_hal_t     *hal;
3375         int             ret;
3376 
3377         TNF_PROBE_0_DEBUG(t1394_initiate_bus_reset_enter,
3378             S1394_TNF_SL_BR_STACK, "");
3379 
3380         ASSERT(t1394_hdl != NULL);
3381 
3382         /* Find the HAL this target resides on */
3383         hal = ((s1394_target_t *)t1394_hdl)->on_hal;
3384 
3385         /* Reset the bus */
3386         if (hal->halinfo.phy == H1394_PHY_1394A) {
3387                 ret = HAL_CALL(hal).short_bus_reset(hal->halinfo.hal_private);
3388                 if (ret != DDI_SUCCESS) {
3389                         TNF_PROBE_1(t1394_initiate_bus_reset_error,
3390                             S1394_TNF_SL_ERROR, "", tnf_string, msg,
3391                             "Error initiating short bus reset");
3392                 }
3393         } else {
3394                 ret = HAL_CALL(hal).bus_reset(hal->halinfo.hal_private);
3395                 if (ret != DDI_SUCCESS) {
3396                         TNF_PROBE_1(t1394_initiate_bus_reset_error,
3397                             S1394_TNF_SL_ERROR, "", tnf_string, msg,
3398                             "Error initiating bus reset");
3399                 }
3400         }
3401 
3402         TNF_PROBE_0_DEBUG(t1394_initiate_bus_reset_exit,
3403             S1394_TNF_SL_BR_STACK, "");
3404 }
3405 
3406 /*
3407  * Function:    t1394_get_topology_map()
3408  * Input(s):    t1394_hdl               The target "handle" returned by
3409  *                                          t1394_attach()
3410  *              bus_generation          The current generation
3411  *              tm_length               The size of the tm_buffer given
3412  *              flags                   The flags parameter is unused (for now)
3413  *
3414  * Output(s):   tm_buffer               Filled in by the 1394 Software Framework
3415  *                                          with the contents of the local
3416  *                                          TOPOLOGY_MAP
3417  *
3418  * Description: t1394_get_topology_map() returns the 1394 TOPLOGY_MAP.  See
3419  *              IEEE 1394-1995 Section 8.2.3.4.1 for format information.  This
3420  *              call can fail if there is a generation mismatch or the
3421  *              tm_buffer is too small to hold the TOPOLOGY_MAP.
3422  */
3423 /* ARGSUSED */
3424 int
3425 t1394_get_topology_map(t1394_handle_t t1394_hdl, uint_t bus_generation,
3426     size_t tm_length, uint_t flags, uint32_t *tm_buffer)
3427 {
3428         s1394_hal_t     *hal;
3429         uint32_t        *tm_ptr;
3430         uint_t          length;
3431 
3432         TNF_PROBE_0_DEBUG(t1394_get_topology_map_enter, S1394_TNF_SL_CSR_STACK,
3433             "");
3434 
3435         ASSERT(t1394_hdl != NULL);
3436 
3437         /* Find the HAL this target resides on */
3438         hal = ((s1394_target_t *)t1394_hdl)->on_hal;
3439 
3440         /* Lock the topology tree */
3441         mutex_enter(&hal->topology_tree_mutex);
3442 
3443         /* Check the bus_generation for the Topology Map */
3444         if (bus_generation != hal->generation_count) {
3445                 /* Unlock the topology tree */
3446                 mutex_exit(&hal->topology_tree_mutex);
3447                 TNF_PROBE_1(t1394_get_topology_map_error,
3448                     S1394_TNF_SL_CSR_ERROR, "", tnf_string, msg,
3449                     "Generation mismatch");
3450                 TNF_PROBE_0_DEBUG(t1394_get_topology_map_exit,
3451                     S1394_TNF_SL_CSR_STACK, "");
3452                 return (DDI_FAILURE);
3453         }
3454 
3455         tm_ptr  = (uint32_t *)hal->CSR_topology_map;
3456         length  = tm_ptr[0] >> 16;
3457         length  = length * 4;   /* Bytes instead of quadlets   */
3458         length  = length + 4;   /* don't forget the first quad */
3459 
3460         /* Check that the buffer is big enough */
3461         if (length > (uint_t)tm_length) {
3462                 /* Unlock the topology tree */
3463                 mutex_exit(&hal->topology_tree_mutex);
3464                 TNF_PROBE_1(t1394_get_topology_map_error,
3465                     S1394_TNF_SL_CSR_ERROR, "", tnf_string, msg,
3466                     "Buffer size too small");
3467                 TNF_PROBE_0_DEBUG(t1394_get_topology_map_exit,
3468                     S1394_TNF_SL_CSR_STACK, "");
3469                 return (DDI_FAILURE);
3470         }
3471 
3472         /* Do the copy */
3473         bcopy(tm_ptr, tm_buffer, length);
3474 
3475         /* Unlock the topology tree */
3476         mutex_exit(&hal->topology_tree_mutex);
3477         TNF_PROBE_0_DEBUG(t1394_get_topology_map_exit, S1394_TNF_SL_CSR_STACK,
3478             "");
3479         return (DDI_SUCCESS);
3480 }
3481 
3482 /*
3483  * Function:    t1394_CRC16()
3484  * Input(s):    d                       The data to compute the CRC-16 for
3485  *              crc_length              The length into the data to compute for
3486  *              flags                   The flags parameter is unused (for now)
3487  *
3488  * Output(s):   CRC                     The CRC-16 computed for the length
3489  *                                          of data specified
3490  *
3491  * Description: t1394_CRC16() implements ISO/IEC 13213:1994, ANSI/IEEE Std
3492  *              1212, 1994 - 8.1.5.
3493  */
3494 /* ARGSUSED */
3495 uint_t
3496 t1394_CRC16(uint32_t *d, size_t crc_length, uint_t flags)
3497 {
3498         /* Implements ISO/IEC 13213:1994,       */
3499         /* ANSI/IEEE Std 1212, 1994 - 8.1.5     */
3500         uint_t  ret;
3501 
3502         TNF_PROBE_0_DEBUG(t1394_CRC16_enter, S1394_TNF_SL_STACK, "");
3503 
3504         ret = s1394_CRC16((uint_t *)d, (uint_t)crc_length);
3505 
3506         TNF_PROBE_0_DEBUG(t1394_CRC16_exit, S1394_TNF_SL_STACK, "");
3507         return (ret);
3508 }
3509 
3510 /*
3511  * Function:    t1394_add_cfgrom_entry()
3512  * Input(s):    t1394_hdl               The target "handle" returned by
3513  *                                          t1394_attach()
3514  *              cfgrom_entryinfo        This structure holds the cfgrom key,
3515  *                                          buffer, and size
3516  *              flags                   The flags parameter is unused (for now)
3517  *
3518  * Output(s):   t1394_cfgrom_hdl        The ConfigROM "handle" used in
3519  *                                          t1394_rem_cfgrom_entry()
3520  *              result                  Used to pass more specific info back
3521  *                                          to target
3522  *
3523  * Description: t1394_add_cfgrom_entry() adds an entry to the local Config ROM,
3524  *              updating the directory entries as necessary.  This call could
3525  *              fail because there is no room for the new entry in Config ROM
3526  *              (T1394_ECFGROM_FULL), the key is invalid (T1394_EINVALID_PARAM),
3527  *              or it was called in interrupt context (T1394_EINVALID_CONTEXT).
3528  */
3529 /* ARGSUSED */
3530 int
3531 t1394_add_cfgrom_entry(t1394_handle_t t1394_hdl,
3532     t1394_cfgrom_entryinfo_t *cfgrom_entryinfo, uint_t flags,
3533     t1394_cfgrom_handle_t *t1394_cfgrom_hdl, int *result)
3534 {
3535         s1394_hal_t     *hal;
3536         s1394_target_t  *target;
3537         int             ret;
3538         uint_t          key;
3539         uint_t          size;
3540         uint32_t        *buffer;
3541 
3542         TNF_PROBE_0_DEBUG(t1394_add_cfgrom_entry_enter,
3543             S1394_TNF_SL_CFGROM_STACK, "");
3544 
3545         ASSERT(t1394_hdl != NULL);
3546 
3547         target = (s1394_target_t *)t1394_hdl;
3548 
3549         key = cfgrom_entryinfo->ce_key;
3550         buffer = cfgrom_entryinfo->ce_buffer;
3551         size = (uint_t)cfgrom_entryinfo->ce_size;
3552 
3553         /* Check for a valid size */
3554         if (size == 0) {
3555                 *result = T1394_EINVALID_PARAM;
3556                 TNF_PROBE_1_DEBUG(t1394_add_cfgrom_entry_error,
3557                     S1394_TNF_SL_CFGROM_ERROR, "", tnf_string, msg,
3558                     "Invalid size of Config ROM buffer (== 0)");
3559                 TNF_PROBE_0_DEBUG(t1394_add_cfgrom_entry_exit,
3560                     S1394_TNF_SL_CFGROM_STACK, "");
3561                 return (DDI_FAILURE);
3562         }
3563 
3564         /* Check for a valid key type */
3565         if (((key << IEEE1212_KEY_VALUE_SHIFT) & IEEE1212_KEY_TYPE_MASK) == 0) {
3566                 *result = T1394_EINVALID_PARAM;
3567                 TNF_PROBE_1_DEBUG(t1394_add_cfgrom_entry_error,
3568                     S1394_TNF_SL_CFGROM_ERROR, "", tnf_string, msg,
3569                     "Invalid key_type in Config ROM key");
3570                 TNF_PROBE_0_DEBUG(t1394_add_cfgrom_entry_exit,
3571                     S1394_TNF_SL_CFGROM_STACK, "");
3572                 return (DDI_FAILURE);
3573         }
3574 
3575         /* Find the HAL this target resides on */
3576         hal = target->on_hal;
3577 
3578         /* Is this on the interrupt stack? */
3579         if (servicing_interrupt()) {
3580                 *result = T1394_EINVALID_CONTEXT;
3581                 TNF_PROBE_0_DEBUG(t1394_add_cfgrom_entry_exit,
3582                     S1394_TNF_SL_CFGROM_STACK, "");
3583                 return (DDI_FAILURE);
3584         }
3585 
3586         /* Lock the Config ROM buffer */
3587         mutex_enter(&hal->local_config_rom_mutex);
3588 
3589         ret = s1394_add_config_rom_entry(hal, key, buffer, size,
3590             (void **)t1394_cfgrom_hdl, result);
3591         if (ret != DDI_SUCCESS) {
3592                 if (*result == CMD1394_ERSRC_CONFLICT)
3593                         *result = T1394_ECFGROM_FULL;
3594                 mutex_exit(&hal->local_config_rom_mutex);
3595 
3596                 TNF_PROBE_1(t1394_add_cfgrom_entry_error,
3597                     S1394_TNF_SL_CFGROM_ERROR, "", tnf_string, msg,
3598                     "Failed in s1394_add_cfgrom_entry()");
3599                 TNF_PROBE_0_DEBUG(t1394_add_cfgrom_entry_exit,
3600                     "stacktrace 1394 s1394", "");
3601                 return (ret);
3602         }
3603 
3604         /* Setup the timeout function */
3605         if (hal->config_rom_timer_set == B_FALSE) {
3606                 hal->config_rom_timer_set = B_TRUE;
3607                 mutex_exit(&hal->local_config_rom_mutex);
3608                 hal->config_rom_timer =
3609                     timeout(s1394_update_config_rom_callback, hal,
3610                         drv_usectohz(CONFIG_ROM_UPDATE_DELAY * 1000));
3611         } else {
3612                 mutex_exit(&hal->local_config_rom_mutex);
3613         }
3614 
3615         TNF_PROBE_0_DEBUG(t1394_add_cfgrom_entry_exit,
3616             S1394_TNF_SL_CFGROM_STACK, "");
3617         return (ret);
3618 }
3619 
3620 /*
3621  * Function:    t1394_rem_cfgrom_entry()
3622  * Input(s):    t1394_hdl               The target "handle" returned by
3623  *                                          t1394_attach()
3624  *              flags                   The flags parameter is unused (for now)
3625  *              t1394_cfgrom_hdl        The ConfigROM "handle" returned by
3626  *                                          t1394_add_cfgrom_entry()
3627  *
3628  * Output(s):   result                  Used to pass more specific info back
3629  *                                          to target
3630  *
3631  * Description: t1394_rem_cfgrom_entry() is used to remove a previously added
3632  *              Config ROM entry (indicated by t1394_cfgrom_hdl).
3633  */
3634 /* ARGSUSED */
3635 int
3636 t1394_rem_cfgrom_entry(t1394_handle_t t1394_hdl, uint_t flags,
3637     t1394_cfgrom_handle_t *t1394_cfgrom_hdl, int *result)
3638 {
3639         s1394_hal_t     *hal;
3640         s1394_target_t  *target;
3641         int             ret;
3642 
3643         TNF_PROBE_0_DEBUG(t1394_rem_cfgrom_entry_enter,
3644             S1394_TNF_SL_CFGROM_STACK, "");
3645 
3646         ASSERT(t1394_hdl != NULL);
3647 
3648         target = (s1394_target_t *)t1394_hdl;
3649 
3650         /* Find the HAL this target resides on */
3651         hal = target->on_hal;
3652 
3653         /* Is this on the interrupt stack? */
3654         if (servicing_interrupt()) {
3655                 *result = T1394_EINVALID_CONTEXT;
3656                 TNF_PROBE_0_DEBUG(t1394_rem_cfgrom_entry_exit,
3657                     S1394_TNF_SL_CFGROM_STACK, "");
3658                 return (DDI_FAILURE);
3659         }
3660 
3661         /* Lock the Config ROM buffer */
3662         mutex_enter(&hal->local_config_rom_mutex);
3663 
3664         ret = s1394_remove_config_rom_entry(hal, (void **)t1394_cfgrom_hdl,
3665             result);
3666         if (ret != DDI_SUCCESS) {
3667                 mutex_exit(&hal->local_config_rom_mutex);
3668                 TNF_PROBE_1(t1394_rem_cfgrom_entry_error,
3669                     S1394_TNF_SL_CFGROM_ERROR, "", tnf_string, msg,
3670                     "Failed in s1394_remove_cfgrom_entry()");
3671                 TNF_PROBE_0_DEBUG(t1394_rem_cfgrom_entry_exit,
3672                     "stacktrace 1394 s1394", "");
3673                 return (ret);
3674         }
3675 
3676         /* Setup the timeout function */
3677         if (hal->config_rom_timer_set == B_FALSE) {
3678                 hal->config_rom_timer_set = B_TRUE;
3679                 mutex_exit(&hal->local_config_rom_mutex);
3680                 hal->config_rom_timer =
3681                     timeout(s1394_update_config_rom_callback, hal,
3682                         drv_usectohz(CONFIG_ROM_UPDATE_DELAY * 1000));
3683         } else {
3684                 mutex_exit(&hal->local_config_rom_mutex);
3685         }
3686 
3687         TNF_PROBE_0_DEBUG(t1394_rem_cfgrom_entry_exit,
3688             S1394_TNF_SL_CFGROM_STACK, "");
3689         return (ret);
3690 }
3691 
3692 /*
3693  * Function:    t1394_get_targetinfo()
3694  * Input(s):    t1394_hdl               The target "handle" returned by
3695  *                                          t1394_attach()
3696  *              bus_generation          The current generation
3697  *              flags                   The flags parameter is unused (for now)
3698  *
3699  * Output(s):   targetinfo              Structure containing max_payload,
3700  *                                          max_speed, and target node ID.
3701  *
3702  * Description: t1394_get_targetinfo() is used to retrieve information specific
3703  *              to a target device.  It will fail if the generation given
3704  *              does not match the current generation.
3705  */
3706 /* ARGSUSED */
3707 int
3708 t1394_get_targetinfo(t1394_handle_t t1394_hdl, uint_t bus_generation,
3709     uint_t flags, t1394_targetinfo_t *targetinfo)
3710 {
3711         s1394_hal_t     *hal;
3712         s1394_target_t  *target;
3713         uint_t          dev;
3714         uint_t          curr;
3715         uint_t          from_node;
3716         uint_t          to_node;
3717 
3718         TNF_PROBE_0_DEBUG(t1394_get_targetinfo_enter, S1394_TNF_SL_STACK, "");
3719 
3720         ASSERT(t1394_hdl != NULL);
3721 
3722         /* Find the HAL this target resides on */
3723         hal = ((s1394_target_t *)t1394_hdl)->on_hal;
3724 
3725         target = (s1394_target_t *)t1394_hdl;
3726 
3727         /* Lock the topology tree */
3728         mutex_enter(&hal->topology_tree_mutex);
3729 
3730         /* Check the bus_generation */
3731         if (bus_generation != hal->generation_count) {
3732                 /* Unlock the topology tree */
3733                 mutex_exit(&hal->topology_tree_mutex);
3734                 TNF_PROBE_3(t1394_get_targetinfo_error, S1394_TNF_SL_STACK, "",
3735                     tnf_string, msg, "Generation mismatch",
3736                     tnf_uint, gen, bus_generation,
3737                     tnf_uint, current_gen, hal->generation_count);
3738                 return (DDI_FAILURE);
3739         }
3740 
3741         rw_enter(&hal->target_list_rwlock, RW_READER);
3742         /*
3743          * If there is no node, report T1394_INVALID_NODEID for target_nodeID;
3744          * current_max_speed and current_max_payload are undefined for this
3745          * case.
3746          */
3747         if (((target->target_state & S1394_TARG_GONE) != 0) ||
3748             (target->on_node == NULL)) {
3749                 targetinfo->target_nodeID = T1394_INVALID_NODEID;
3750                 TNF_PROBE_1_DEBUG(t1394_get_targetinfo_exit,
3751                     S1394_TNF_SL_STACK, "", tnf_string, msg, "No device");
3752         } else {
3753                 targetinfo->target_nodeID =
3754                     (target->on_hal->node_id & IEEE1394_BUS_NUM_MASK) |
3755                     target->on_node->node_num;
3756 
3757                 from_node = (target->on_hal->node_id) & IEEE1394_NODE_NUM_MASK;
3758                 to_node = target->on_node->node_num;
3759 
3760                 targetinfo->current_max_speed = (uint_t)s1394_speed_map_get(
3761                     hal, from_node, to_node);
3762 
3763                 /* Get current_max_payload */
3764                 s1394_get_maxpayload(target, &dev, &curr);
3765                 targetinfo->current_max_payload      = curr;
3766 
3767                 TNF_PROBE_3_DEBUG(t1394_get_targetinfo_exit,
3768                     S1394_TNF_SL_STACK, "",
3769                     tnf_uint, payload, targetinfo->current_max_payload,
3770                     tnf_uint, speed, targetinfo->current_max_speed,
3771                     tnf_uint, nodeid, targetinfo->target_nodeID);
3772         }
3773 
3774         rw_exit(&hal->target_list_rwlock);
3775         /* Unlock the topology tree */
3776         mutex_exit(&hal->topology_tree_mutex);
3777         return (DDI_SUCCESS);
3778 }