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