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