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 kmem_free(member_new, sizeof (s1394_isoch_cec_member_t)); 1848 /* Unlock the Isoch CEC member list */ 1849 mutex_exit(&cec_curr->isoch_cec_mutex); 1850 return (DDI_FAILURE); 1851 } 1852 1853 /* Copy the events information into the struct */ 1854 member_new->isoch_cec_evts = join_isoch_info->isoch_cec_evts; 1855 member_new->isoch_cec_evts_arg = join_isoch_info->isoch_cec_evts_arg; 1856 member_new->cec_mem_options = join_isoch_info->jii_options; 1857 member_new->cec_mem_target = (s1394_target_t *)t1394_hdl; 1858 1859 /* Insert new member into Isoch CEC's member list */ 1860 s1394_isoch_cec_member_list_insert(hal, cec_curr, member_new); 1861 1862 /* Update the channel mask filter */ 1863 cec_curr->filter_channel_mask = check_mask; 1864 1865 /* Update the speed filter */ 1866 cec_curr->filter_current_speed = curr_max_speed; 1867 1868 /* Update the talker pointer (if necessary) */ 1869 if (join_isoch_info->jii_options & T1394_TALKER) 1870 cec_curr->cec_member_talker = cec_curr->cec_member_list_head; 1871 1872 /* 1873 * Now "leave" is a legal state transition 1874 * and "free" is an illegal state transition 1875 */ 1876 CEC_SET_LEGAL(cec_curr, ISOCH_CEC_LEAVE); 1877 CEC_SET_ILLEGAL(cec_curr, ISOCH_CEC_FREE); 1878 1879 /* Unlock the Isoch CEC member list */ 1880 mutex_exit(&cec_curr->isoch_cec_mutex); 1881 1882 return (DDI_SUCCESS); 1883 } 1884 1885 /* 1886 * Function: t1394_leave_isoch_cec() 1887 * Input(s): t1394_hdl The target "handle" returned by 1888 * t1394_attach() 1889 * t1394_isoch_cec_hdl The Isoch CEC "handle" returned by 1890 * t1394_alloc_isoch_cec() 1891 * flags The flags parameter is unused (for now) 1892 * 1893 * Output(s): DDI_SUCCESS Target successfully left the 1894 * Isoch CEC 1895 * DDI_FAILURE Target failed to leave the Isoch CEC 1896 * 1897 * Description: t1394_leave_isoch_cec() is used by a target driver to remove 1898 * itself from the Isoch CEC's member list. It is possible 1899 * for this call to fail because the target is not found in 1900 * the current member list, or because it is not an appropriate 1901 * time for a target to leave. 1902 */ 1903 /* ARGSUSED */ 1904 int 1905 t1394_leave_isoch_cec(t1394_handle_t t1394_hdl, 1906 t1394_isoch_cec_handle_t t1394_isoch_cec_hdl, uint_t flags) 1907 { 1908 s1394_hal_t *hal; 1909 s1394_isoch_cec_t *cec_curr; 1910 s1394_isoch_cec_member_t *member_curr; 1911 s1394_isoch_cec_member_t *member_temp; 1912 boolean_t found; 1913 uint64_t temp_channel_mask; 1914 uint_t temp_max_speed; 1915 1916 ASSERT(t1394_hdl != NULL); 1917 ASSERT(t1394_isoch_cec_hdl != NULL); 1918 1919 hal = ((s1394_target_t *)t1394_hdl)->on_hal; 1920 1921 /* Convert the handle to an Isoch CEC pointer */ 1922 cec_curr = (s1394_isoch_cec_t *)t1394_isoch_cec_hdl; 1923 1924 /* Lock the Isoch CEC member list */ 1925 mutex_enter(&cec_curr->isoch_cec_mutex); 1926 1927 /* Are we in any callbacks? (Wait for them to finish) */ 1928 while (CEC_IN_ANY_CALLBACKS(cec_curr)) { 1929 cec_curr->cec_want_wakeup = B_TRUE; 1930 cv_wait(&cec_curr->in_callbacks_cv, 1931 &cec_curr->isoch_cec_mutex); 1932 } 1933 1934 /* Is "leave" a legal state transition? */ 1935 if (CEC_TRANSITION_LEGAL(cec_curr, ISOCH_CEC_LEAVE) == 0) { 1936 /* Unlock the Isoch CEC member list */ 1937 mutex_exit(&cec_curr->isoch_cec_mutex); 1938 return (DDI_FAILURE); 1939 } 1940 1941 /* Find the Target on the CEC's member list */ 1942 found = B_FALSE; 1943 temp_channel_mask = cec_curr->cec_alloc_props.cec_channel_mask; 1944 temp_max_speed = cec_curr->cec_alloc_props.cec_max_speed; 1945 member_curr = cec_curr->cec_member_list_head; 1946 while (member_curr != NULL) { 1947 if (member_curr->cec_mem_target == 1948 (s1394_target_t *)t1394_hdl) { 1949 member_temp = member_curr; 1950 found = B_TRUE; 1951 } else { 1952 /* Keep track of channel mask and max speed info */ 1953 temp_channel_mask &= member_curr->req_channel_mask; 1954 if (member_curr->req_max_speed < temp_max_speed) 1955 temp_max_speed = member_curr->req_max_speed; 1956 } 1957 member_curr = member_curr->cec_mem_next; 1958 } 1959 1960 /* Target not found on this Isoch CEC */ 1961 if (found == B_FALSE) { 1962 /* Unlock the Isoch CEC member list */ 1963 mutex_exit(&cec_curr->isoch_cec_mutex); 1964 return (DDI_FAILURE); 1965 } else { 1966 /* This member's departure may change filter constraints */ 1967 cec_curr->filter_current_speed = temp_max_speed; 1968 cec_curr->filter_channel_mask = temp_channel_mask; 1969 } 1970 1971 /* Remove member from Isoch CEC's member list */ 1972 s1394_isoch_cec_member_list_remove(hal, cec_curr, member_temp); 1973 1974 /* If we are removing the talker, then update the pointer */ 1975 if (cec_curr->cec_member_talker == member_temp) 1976 cec_curr->cec_member_talker = NULL; 1977 1978 /* Is the Isoch CEC's member list empty? */ 1979 if ((cec_curr->cec_member_list_head == NULL) && 1980 (cec_curr->cec_member_list_tail == NULL)) { 1981 /* 1982 * Now "free" _might_ be a legal state transition 1983 * if we aren't in setup or start phases and "leave" 1984 * is definitely an illegal state transition 1985 */ 1986 if (CEC_TRANSITION_LEGAL(cec_curr, ISOCH_CEC_JOIN) != 0) 1987 CEC_SET_LEGAL(cec_curr, ISOCH_CEC_FREE); 1988 CEC_SET_ILLEGAL(cec_curr, ISOCH_CEC_LEAVE); 1989 } 1990 1991 /* Unlock the Isoch CEC member list */ 1992 mutex_exit(&cec_curr->isoch_cec_mutex); 1993 1994 /* Free the Isoch CEC member structure */ 1995 kmem_free(member_temp, sizeof (s1394_isoch_cec_member_t)); 1996 1997 return (DDI_SUCCESS); 1998 } 1999 2000 /* 2001 * Function: t1394_setup_isoch_cec() 2002 * Input(s): t1394_hdl The target "handle" returned by 2003 * t1394_attach() 2004 * t1394_isoch_cec_hdl The Isoch CEC "handle" returned by 2005 * t1394_alloc_isoch_cec() 2006 * flags The flags parameter is unused (for now) 2007 * 2008 * Output(s): result Used to pass more specific info back 2009 * to target 2010 * 2011 * Description: t1394_setup_isoch_cec() directs the 1394 Software Framework 2012 * to allocate isochronous resources and invoke the setup_target() 2013 * callback for each member of the Isoch CEC. This call may 2014 * fail because bandwidth was unavailable (T1394_ENO_BANDWIDTH), 2015 * channels were unavailable (T1394_ENO_CHANNEL), or one of the 2016 * member targets returned failure from its setup_target() 2017 * callback. 2018 */ 2019 /* ARGSUSED */ 2020 int 2021 t1394_setup_isoch_cec(t1394_handle_t t1394_hdl, 2022 t1394_isoch_cec_handle_t t1394_isoch_cec_hdl, uint_t flags, int *result) 2023 { 2024 s1394_hal_t *hal; 2025 s1394_isoch_cec_t *cec_curr; 2026 s1394_isoch_cec_member_t *member_curr; 2027 t1394_setup_target_args_t target_args; 2028 uint64_t temp_chnl_mask; 2029 uint32_t old_chnl; 2030 uint32_t try_chnl; 2031 uint_t bw_alloc_units; 2032 uint_t generation; 2033 int chnl_num; 2034 int err; 2035 int ret; 2036 int j; 2037 int (*setup_callback)(t1394_isoch_cec_handle_t, opaque_t, 2038 t1394_setup_target_args_t *); 2039 2040 ASSERT(t1394_hdl != NULL); 2041 ASSERT(t1394_isoch_cec_hdl != NULL); 2042 2043 hal = ((s1394_target_t *)t1394_hdl)->on_hal; 2044 2045 /* Convert the handle to an Isoch CEC pointer */ 2046 cec_curr = (s1394_isoch_cec_t *)t1394_isoch_cec_hdl; 2047 2048 /* Lock the Isoch CEC member list */ 2049 mutex_enter(&cec_curr->isoch_cec_mutex); 2050 2051 /* Are we in any callbacks? */ 2052 if (CEC_IN_ANY_CALLBACKS(cec_curr)) { 2053 /* Unlock the Isoch CEC member list */ 2054 mutex_exit(&cec_curr->isoch_cec_mutex); 2055 return (DDI_FAILURE); 2056 } 2057 2058 /* Is "setup" a legal state transition? */ 2059 if (CEC_TRANSITION_LEGAL(cec_curr, ISOCH_CEC_SETUP) == 0) { 2060 /* Unlock the Isoch CEC member list */ 2061 mutex_exit(&cec_curr->isoch_cec_mutex); 2062 return (DDI_FAILURE); 2063 } 2064 2065 /* If T1394_NO_IRM_ALLOC is set then don't allocate... do callbacks */ 2066 if (cec_curr->cec_options & T1394_NO_IRM_ALLOC) { 2067 goto setup_do_callbacks; 2068 } 2069 2070 /* Allocate bandwidth and channels */ 2071 for (j = 0; j < S1394_ISOCH_ALLOC_RETRIES; j++) { 2072 /* 2073 * Get the current generation number - don't 2074 * need the lock because we are read only here 2075 */ 2076 generation = hal->generation_count; 2077 2078 /* Compute how much bandwidth is needed */ 2079 bw_alloc_units = s1394_compute_bw_alloc_units(hal, 2080 cec_curr->bandwidth, cec_curr->filter_current_speed); 2081 2082 /* Check that the generation has not changed - */ 2083 /* don't need the lock (read only) */ 2084 if (generation != hal->generation_count) 2085 continue; 2086 2087 /* Unlock the Isoch CEC member list */ 2088 mutex_exit(&cec_curr->isoch_cec_mutex); 2089 2090 /* Try to allocate the bandwidth */ 2091 ret = s1394_bandwidth_alloc(hal, bw_alloc_units, generation, 2092 &err); 2093 2094 /* Lock the Isoch CEC member list */ 2095 mutex_enter(&cec_curr->isoch_cec_mutex); 2096 2097 /* If there was a bus reset, start over */ 2098 if (ret == DDI_FAILURE) { 2099 if (err == CMD1394_EBUSRESET) { 2100 continue; /* start over and try again */ 2101 } else { 2102 *result = T1394_ENO_BANDWIDTH; 2103 /* Unlock the Isoch CEC member list */ 2104 mutex_exit(&cec_curr->isoch_cec_mutex); 2105 return (DDI_FAILURE); 2106 } 2107 } 2108 2109 /* Check that the generation has not changed - */ 2110 /* don't need the lock (read only) */ 2111 if (generation != hal->generation_count) 2112 continue; 2113 2114 /* 2115 * Allocate a channel 2116 * From IEEE 1394-1995, Section 8.3.2.3.8: "Bits 2117 * allocated in the CHANNELS_AVAILABLE_HI field of 2118 * this register shall start at bit zero (channel 2119 * number zero), and additional channel numbers shall 2120 * be represented in a monotonically increasing sequence 2121 * of bit numbers up to a maximum of bit 31 (channel 2122 * number 31). Bits allocated in the CHANNELS_AVAILABLE_LO 2123 * field of this register shall start at bit zero 2124 * (channel number 32), and additional channel numbers 2125 * shall be represented in a monotonically increasing 2126 * sequence of bit numbers up to a maximum of bit 31 2127 * (channel number 63). 2128 */ 2129 temp_chnl_mask = cec_curr->filter_channel_mask; 2130 for (chnl_num = 63; chnl_num >= 0; chnl_num--) { 2131 if ((temp_chnl_mask & 1) == 1) { 2132 try_chnl = (1 << ((63 - chnl_num) % 32)); 2133 2134 /* Unlock the Isoch CEC member list */ 2135 mutex_exit(&cec_curr->isoch_cec_mutex); 2136 if (chnl_num < 32) { 2137 ret = s1394_channel_alloc(hal, 2138 try_chnl, generation, 2139 S1394_CHANNEL_ALLOC_HI, &old_chnl, 2140 &err); 2141 } else { 2142 ret = s1394_channel_alloc(hal, 2143 try_chnl, generation, 2144 S1394_CHANNEL_ALLOC_LO, &old_chnl, 2145 &err); 2146 } 2147 /* Lock the Isoch CEC member list */ 2148 mutex_enter(&cec_curr->isoch_cec_mutex); 2149 2150 /* Did we get a channel? (or a bus reset) */ 2151 if ((ret == DDI_SUCCESS) || 2152 (err == CMD1394_EBUSRESET)) 2153 break; 2154 } 2155 temp_chnl_mask = temp_chnl_mask >> 1; 2156 } 2157 2158 /* If we've tried all the possible channels, then fail */ 2159 if (chnl_num == 0) { 2160 *result = T1394_ENO_CHANNEL; 2161 /* 2162 * If we successfully allocate bandwidth, and 2163 * then fail getting a channel, we need to 2164 * free up the bandwidth 2165 */ 2166 2167 /* Check that the generation has not changed */ 2168 /* lock not needed here (read only) */ 2169 if (generation != hal->generation_count) 2170 continue; 2171 2172 /* Unlock the Isoch CEC member list */ 2173 mutex_exit(&cec_curr->isoch_cec_mutex); 2174 2175 /* Try to free up the bandwidth */ 2176 ret = s1394_bandwidth_free(hal, bw_alloc_units, 2177 generation, &err); 2178 2179 /* Lock the Isoch CEC member list */ 2180 mutex_enter(&cec_curr->isoch_cec_mutex); 2181 2182 if (ret == DDI_FAILURE) { 2183 if (err == CMD1394_EBUSRESET) { 2184 continue; 2185 } 2186 } 2187 2188 /* Unlock the Isoch CEC member list */ 2189 mutex_exit(&cec_curr->isoch_cec_mutex); 2190 return (DDI_FAILURE); 2191 } 2192 2193 /* If we got a channel, we're done (else start over) */ 2194 if (ret == DDI_SUCCESS) 2195 break; 2196 else if (err == CMD1394_EBUSRESET) 2197 continue; 2198 } 2199 2200 /* Have we gotten too many bus resets? */ 2201 if (j == S1394_ISOCH_ALLOC_RETRIES) { 2202 *result = T1394_ENO_BANDWIDTH; 2203 /* Unlock the Isoch CEC member list */ 2204 mutex_exit(&cec_curr->isoch_cec_mutex); 2205 return (DDI_FAILURE); 2206 } 2207 2208 cec_curr->realloc_valid = B_TRUE; 2209 cec_curr->realloc_chnl_num = chnl_num; 2210 cec_curr->realloc_bandwidth = cec_curr->bandwidth; 2211 cec_curr->realloc_speed = cec_curr->filter_current_speed; 2212 2213 setup_do_callbacks: 2214 /* Call all of the setup_target() callbacks */ 2215 target_args.channel_num = chnl_num; 2216 target_args.channel_speed = cec_curr->filter_current_speed; 2217 2218 /* Now we are going into the callbacks */ 2219 cec_curr->in_callbacks = B_TRUE; 2220 2221 /* Unlock the Isoch CEC member list */ 2222 mutex_exit(&cec_curr->isoch_cec_mutex); 2223 2224 member_curr = cec_curr->cec_member_list_head; 2225 *result = 0; 2226 while (member_curr != NULL) { 2227 if (member_curr->isoch_cec_evts.setup_target != NULL) { 2228 setup_callback = 2229 member_curr->isoch_cec_evts.setup_target; 2230 ret = setup_callback(t1394_isoch_cec_hdl, 2231 member_curr->isoch_cec_evts_arg, &target_args); 2232 if (ret != DDI_SUCCESS) 2233 *result = T1394_ETARGET; 2234 } 2235 member_curr = member_curr->cec_mem_next; 2236 } 2237 2238 /* Lock the Isoch CEC member list */ 2239 mutex_enter(&cec_curr->isoch_cec_mutex); 2240 2241 /* We are finished with the callbacks */ 2242 cec_curr->in_callbacks = B_FALSE; 2243 if (cec_curr->cec_want_wakeup == B_TRUE) { 2244 cec_curr->cec_want_wakeup = B_FALSE; 2245 cv_broadcast(&cec_curr->in_callbacks_cv); 2246 } 2247 2248 /* 2249 * Now "start" and "teardown" are legal state transitions 2250 * and "join", "free", and "setup" are illegal state transitions 2251 */ 2252 CEC_SET_LEGAL(cec_curr, (ISOCH_CEC_START | ISOCH_CEC_TEARDOWN)); 2253 CEC_SET_ILLEGAL(cec_curr, (ISOCH_CEC_JOIN | ISOCH_CEC_FREE | 2254 ISOCH_CEC_SETUP)); 2255 2256 /* Unlock the Isoch CEC member list */ 2257 mutex_exit(&cec_curr->isoch_cec_mutex); 2258 2259 /* Return DDI_FAILURE if any targets failed setup */ 2260 if (*result != 0) { 2261 return (DDI_FAILURE); 2262 } 2263 2264 return (DDI_SUCCESS); 2265 } 2266 2267 /* 2268 * Function: t1394_start_isoch_cec() 2269 * Input(s): t1394_hdl The target "handle" returned by 2270 * t1394_attach() 2271 * t1394_isoch_cec_hdl The Isoch CEC "handle" returned by 2272 * t1394_alloc_isoch_cec() 2273 * flags The flags parameter is unused (for now) 2274 * 2275 * Output(s): DDI_SUCCESS All start_target() callbacks returned 2276 * successfully 2277 * DDI_FAILURE One or more start_target() callbacks 2278 * returned failure 2279 * 2280 * Description: t1394_start_isoch_cec() directs the 1394 Software Framework 2281 * to invoke each of the start_target() callbacks, first for 2282 * each listener, then for the talker. 2283 */ 2284 /* ARGSUSED */ 2285 int 2286 t1394_start_isoch_cec(t1394_handle_t t1394_hdl, 2287 t1394_isoch_cec_handle_t t1394_isoch_cec_hdl, uint_t flags) 2288 { 2289 s1394_isoch_cec_t *cec_curr; 2290 s1394_isoch_cec_member_t *member_curr; 2291 int ret; 2292 boolean_t err; 2293 int (*start_callback)(t1394_isoch_cec_handle_t, opaque_t); 2294 2295 ASSERT(t1394_hdl != NULL); 2296 ASSERT(t1394_isoch_cec_hdl != NULL); 2297 2298 /* Convert the handle to an Isoch CEC pointer */ 2299 cec_curr = (s1394_isoch_cec_t *)t1394_isoch_cec_hdl; 2300 2301 /* Lock the Isoch CEC member list */ 2302 mutex_enter(&cec_curr->isoch_cec_mutex); 2303 2304 /* Are we in any callbacks? */ 2305 if (CEC_IN_ANY_CALLBACKS(cec_curr)) { 2306 /* Unlock the Isoch CEC member list */ 2307 mutex_exit(&cec_curr->isoch_cec_mutex); 2308 return (DDI_FAILURE); 2309 } 2310 2311 /* Is "start" a legal state transition? */ 2312 if (CEC_TRANSITION_LEGAL(cec_curr, ISOCH_CEC_START) == 0) { 2313 /* Unlock the Isoch CEC member list */ 2314 mutex_exit(&cec_curr->isoch_cec_mutex); 2315 return (DDI_FAILURE); 2316 } 2317 2318 /* Now we are going into the callbacks */ 2319 cec_curr->in_callbacks = B_TRUE; 2320 2321 /* Unlock the Isoch CEC member list */ 2322 mutex_exit(&cec_curr->isoch_cec_mutex); 2323 2324 /* 2325 * Call all of the start_target() callbacks 2326 * Start at the tail (listeners first) and 2327 * go toward the head (talker last) 2328 */ 2329 member_curr = cec_curr->cec_member_list_tail; 2330 err = B_FALSE; 2331 while (member_curr != NULL) { 2332 if (member_curr->isoch_cec_evts.start_target != NULL) { 2333 start_callback = 2334 member_curr->isoch_cec_evts.start_target; 2335 ret = start_callback(t1394_isoch_cec_hdl, 2336 member_curr->isoch_cec_evts_arg); 2337 if (ret != DDI_SUCCESS) 2338 err = B_TRUE; 2339 } 2340 member_curr = member_curr->cec_mem_prev; 2341 } 2342 2343 /* Lock the Isoch CEC member list */ 2344 mutex_enter(&cec_curr->isoch_cec_mutex); 2345 2346 /* We are finished with the callbacks */ 2347 cec_curr->in_callbacks = B_FALSE; 2348 if (cec_curr->cec_want_wakeup == B_TRUE) { 2349 cec_curr->cec_want_wakeup = B_FALSE; 2350 cv_broadcast(&cec_curr->in_callbacks_cv); 2351 } 2352 2353 /* 2354 * Now "stop" is a legal state transitions 2355 * and "start" and "teardown" are illegal state transitions 2356 */ 2357 CEC_SET_LEGAL(cec_curr, ISOCH_CEC_STOP); 2358 CEC_SET_ILLEGAL(cec_curr, (ISOCH_CEC_START | ISOCH_CEC_TEARDOWN)); 2359 2360 /* Unlock the Isoch CEC member list */ 2361 mutex_exit(&cec_curr->isoch_cec_mutex); 2362 2363 /* Return DDI_FAILURE if any targets failed start */ 2364 if (err == B_TRUE) { 2365 return (DDI_FAILURE); 2366 } 2367 2368 return (DDI_SUCCESS); 2369 } 2370 2371 /* 2372 * Function: t1394_stop_isoch_cec() 2373 * Input(s): t1394_hdl The target "handle" returned by 2374 * t1394_attach() 2375 * t1394_isoch_cec_hdl The Isoch CEC "handle" returned by 2376 * t1394_alloc_isoch_cec() 2377 * flags The flags parameter is unused (for now) 2378 * 2379 * Output(s): DDI_SUCCESS Target successfully stopped the 2380 * Isoch CEC 2381 * DDI_FAILURE Target failed to stop the Isoch CEC 2382 * 2383 * Description: t1394_stop_isoch_cec() directs the 1394 Software Framework 2384 * to invoke each of the stop_target() callbacks, first for 2385 * the talker, then for each listener. 2386 * (This call will fail if it is called at an 2387 * inappropriate time, i.e. before the t1394_start_isoch_cec() 2388 * call, etc.) 2389 */ 2390 /* ARGSUSED */ 2391 int 2392 t1394_stop_isoch_cec(t1394_handle_t t1394_hdl, 2393 t1394_isoch_cec_handle_t t1394_isoch_cec_hdl, uint_t flags) 2394 { 2395 s1394_isoch_cec_t *cec_curr; 2396 s1394_isoch_cec_member_t *member_curr; 2397 void (*stop_callback)(t1394_isoch_cec_handle_t, opaque_t); 2398 2399 ASSERT(t1394_hdl != NULL); 2400 ASSERT(t1394_isoch_cec_hdl != NULL); 2401 2402 /* Convert the handle to an Isoch CEC pointer */ 2403 cec_curr = (s1394_isoch_cec_t *)t1394_isoch_cec_hdl; 2404 2405 /* Lock the Isoch CEC member list */ 2406 mutex_enter(&cec_curr->isoch_cec_mutex); 2407 2408 /* Are we in any callbacks? */ 2409 if (CEC_IN_ANY_CALLBACKS(cec_curr)) { 2410 /* Unlock the Isoch CEC member list */ 2411 mutex_exit(&cec_curr->isoch_cec_mutex); 2412 return (DDI_FAILURE); 2413 } 2414 2415 /* Is "stop" a legal state transition? */ 2416 if (CEC_TRANSITION_LEGAL(cec_curr, ISOCH_CEC_STOP) == 0) { 2417 /* Unlock the Isoch CEC member list */ 2418 mutex_exit(&cec_curr->isoch_cec_mutex); 2419 return (DDI_FAILURE); 2420 } 2421 2422 /* Now we are going into the callbacks */ 2423 cec_curr->in_callbacks = B_TRUE; 2424 2425 /* Unlock the Isoch CEC member list */ 2426 mutex_exit(&cec_curr->isoch_cec_mutex); 2427 2428 /* 2429 * Call all of the stop_target() callbacks 2430 * Start at the head (talker first) and 2431 * go toward the tail (listeners last) 2432 */ 2433 member_curr = cec_curr->cec_member_list_head; 2434 while (member_curr != NULL) { 2435 if (member_curr->isoch_cec_evts.stop_target != NULL) { 2436 stop_callback = 2437 member_curr->isoch_cec_evts.stop_target; 2438 stop_callback(t1394_isoch_cec_hdl, 2439 member_curr->isoch_cec_evts_arg); 2440 } 2441 member_curr = member_curr->cec_mem_next; 2442 } 2443 2444 /* Lock the Isoch CEC member list */ 2445 mutex_enter(&cec_curr->isoch_cec_mutex); 2446 2447 /* We are finished with the callbacks */ 2448 cec_curr->in_callbacks = B_FALSE; 2449 if (cec_curr->cec_want_wakeup == B_TRUE) { 2450 cec_curr->cec_want_wakeup = B_FALSE; 2451 cv_broadcast(&cec_curr->in_callbacks_cv); 2452 } 2453 2454 /* 2455 * Now "start" and "teardown" are legal state transitions 2456 * and "stop" is an illegal state transitions 2457 */ 2458 CEC_SET_LEGAL(cec_curr, (ISOCH_CEC_START | ISOCH_CEC_TEARDOWN)); 2459 CEC_SET_ILLEGAL(cec_curr, ISOCH_CEC_STOP); 2460 2461 /* Unlock the Isoch CEC member list */ 2462 mutex_exit(&cec_curr->isoch_cec_mutex); 2463 2464 return (DDI_SUCCESS); 2465 } 2466 2467 /* 2468 * Function: t1394_teardown_isoch_cec() 2469 * Input(s): t1394_hdl The target "handle" returned by 2470 * t1394_attach() 2471 * t1394_isoch_cec_hdl The Isoch CEC "handle" returned by 2472 * t1394_alloc_isoch_cec() 2473 * flags The flags parameter is unused (for now) 2474 * 2475 * Output(s): DDI_SUCCESS Target successfully tore down the 2476 * Isoch CEC 2477 * DDI_FAILURE Target failed to tear down the 2478 * Isoch CEC 2479 * 2480 * Description: t1394_teardown_isoch_cec() directs the 1394 Software Framework 2481 * to free up any isochronous resources we might be holding and 2482 * call all of the teardown_target() callbacks. 2483 * (This call will fail if it is called at an 2484 * inappropriate time, i.e. before the t1394_start_isoch_cec() 2485 * call, before the t1394_stop_isoch_cec, etc. 2486 */ 2487 /* ARGSUSED */ 2488 int 2489 t1394_teardown_isoch_cec(t1394_handle_t t1394_hdl, 2490 t1394_isoch_cec_handle_t t1394_isoch_cec_hdl, uint_t flags) 2491 { 2492 s1394_hal_t *hal; 2493 s1394_isoch_cec_t *cec_curr; 2494 s1394_isoch_cec_member_t *member_curr; 2495 uint32_t chnl_mask; 2496 uint32_t old_chnl_mask; 2497 uint_t bw_alloc_units; 2498 uint_t generation; 2499 int ret; 2500 int err; 2501 void (*teardown_callback)(t1394_isoch_cec_handle_t, opaque_t); 2502 2503 ASSERT(t1394_hdl != NULL); 2504 ASSERT(t1394_isoch_cec_hdl != NULL); 2505 2506 hal = ((s1394_target_t *)t1394_hdl)->on_hal; 2507 2508 /* Convert the handle to an Isoch CEC pointer */ 2509 cec_curr = (s1394_isoch_cec_t *)t1394_isoch_cec_hdl; 2510 2511 /* Lock the Isoch CEC member list */ 2512 mutex_enter(&cec_curr->isoch_cec_mutex); 2513 2514 /* Are we in any callbacks? */ 2515 if (CEC_IN_ANY_CALLBACKS(cec_curr)) { 2516 /* Unlock the Isoch CEC member list */ 2517 mutex_exit(&cec_curr->isoch_cec_mutex); 2518 return (DDI_FAILURE); 2519 } 2520 2521 /* Is "teardown" a legal state transition? */ 2522 if (CEC_TRANSITION_LEGAL(cec_curr, ISOCH_CEC_TEARDOWN) == 0) { 2523 /* Unlock the Isoch CEC member list */ 2524 mutex_exit(&cec_curr->isoch_cec_mutex); 2525 return (DDI_FAILURE); 2526 } 2527 2528 /* If T1394_NO_IRM_ALLOC is set then don't free... do callbacks */ 2529 if (cec_curr->cec_options & T1394_NO_IRM_ALLOC) { 2530 goto teardown_do_callbacks; 2531 } 2532 2533 /* If nothing has been allocated or we failed to */ 2534 /* reallocate, then we are done... call the callbacks */ 2535 if ((cec_curr->realloc_valid == B_FALSE) || 2536 (cec_curr->realloc_failed == B_TRUE)) { 2537 goto teardown_do_callbacks; 2538 } 2539 2540 /* 2541 * Get the current generation number - don't need the 2542 * topology tree mutex here because it is read-only, and 2543 * there is a race condition with or without it. 2544 */ 2545 generation = hal->generation_count; 2546 2547 /* Compute the amount bandwidth to free */ 2548 bw_alloc_units = s1394_compute_bw_alloc_units(hal, 2549 cec_curr->bandwidth, cec_curr->realloc_speed); 2550 2551 /* Check that the generation has not changed - */ 2552 /* don't need the lock (read only) */ 2553 if (generation != hal->generation_count) 2554 goto teardown_do_callbacks; 2555 2556 /* Unlock the Isoch CEC member list */ 2557 mutex_exit(&cec_curr->isoch_cec_mutex); 2558 2559 /* Try to free up the bandwidth */ 2560 ret = s1394_bandwidth_free(hal, bw_alloc_units, generation, &err); 2561 2562 /* Lock the Isoch CEC member list */ 2563 mutex_enter(&cec_curr->isoch_cec_mutex); 2564 2565 if (ret == DDI_FAILURE) { 2566 if (err == CMD1394_EBUSRESET) { 2567 goto teardown_do_callbacks; 2568 } 2569 } 2570 2571 /* Free the allocated channel */ 2572 chnl_mask = (1 << ((63 - cec_curr->realloc_chnl_num) % 32)); 2573 2574 /* Unlock the Isoch CEC member list */ 2575 mutex_exit(&cec_curr->isoch_cec_mutex); 2576 if (cec_curr->realloc_chnl_num < 32) { 2577 ret = s1394_channel_free(hal, chnl_mask, generation, 2578 S1394_CHANNEL_ALLOC_HI, &old_chnl_mask, &err); 2579 } else { 2580 ret = s1394_channel_free(hal, chnl_mask, generation, 2581 S1394_CHANNEL_ALLOC_LO, &old_chnl_mask, &err); 2582 } 2583 /* Lock the Isoch CEC member list */ 2584 mutex_enter(&cec_curr->isoch_cec_mutex); 2585 2586 teardown_do_callbacks: 2587 /* From here on reallocation is unnecessary */ 2588 cec_curr->realloc_valid = B_FALSE; 2589 cec_curr->realloc_chnl_num = 0; 2590 cec_curr->realloc_bandwidth = 0; 2591 2592 /* Now we are going into the callbacks */ 2593 cec_curr->in_callbacks = B_TRUE; 2594 2595 /* Unlock the Isoch CEC member list */ 2596 mutex_exit(&cec_curr->isoch_cec_mutex); 2597 2598 /* Call all of the teardown_target() callbacks */ 2599 member_curr = cec_curr->cec_member_list_head; 2600 while (member_curr != NULL) { 2601 if (member_curr->isoch_cec_evts.teardown_target != NULL) { 2602 teardown_callback = 2603 member_curr->isoch_cec_evts.teardown_target; 2604 teardown_callback(t1394_isoch_cec_hdl, 2605 member_curr->isoch_cec_evts_arg); 2606 } 2607 member_curr = member_curr->cec_mem_next; 2608 } 2609 2610 /* Lock the Isoch CEC member list */ 2611 mutex_enter(&cec_curr->isoch_cec_mutex); 2612 2613 /* We are finished with the callbacks */ 2614 cec_curr->in_callbacks = B_FALSE; 2615 if (cec_curr->cec_want_wakeup == B_TRUE) { 2616 cec_curr->cec_want_wakeup = B_FALSE; 2617 cv_broadcast(&cec_curr->in_callbacks_cv); 2618 } 2619 2620 /* 2621 * Now "join" and "setup" are legal state transitions 2622 * and "start" and "teardown" are illegal state transitions 2623 */ 2624 CEC_SET_LEGAL(cec_curr, (ISOCH_CEC_JOIN | ISOCH_CEC_SETUP)); 2625 CEC_SET_ILLEGAL(cec_curr, (ISOCH_CEC_START | ISOCH_CEC_TEARDOWN)); 2626 2627 /* And if the member list is empty, then "free" is legal too */ 2628 if ((cec_curr->cec_member_list_head == NULL) && 2629 (cec_curr->cec_member_list_tail == NULL)) { 2630 CEC_SET_LEGAL(cec_curr, ISOCH_CEC_FREE); 2631 } 2632 2633 /* Unlock the Isoch CEC member list */ 2634 mutex_exit(&cec_curr->isoch_cec_mutex); 2635 return (DDI_SUCCESS); 2636 } 2637 2638 /* 2639 * Function: t1394_alloc_isoch_dma() 2640 * Input(s): t1394_hdl The target "handle" returned by 2641 * t1394_attach() 2642 * idi This structure contains information 2643 * for configuring the data flow for 2644 * isochronous DMA 2645 * flags The flags parameter is unused (for now) 2646 * 2647 * Output(s): t1394_idma_hdl The IDMA "handle" used in all 2648 * subsequent isoch_dma() calls 2649 * result Used to pass more specific info back 2650 * to target 2651 * 2652 * Description: t1394_alloc_isoch_dma() allocates and initializes an 2653 * isochronous DMA resource for transmitting or receiving 2654 * isochronous data. If it fails, result may hold 2655 * T1394_EIDMA_NO_RESRCS, indicating that no isoch DMA resource 2656 * are available. 2657 */ 2658 /* ARGSUSED */ 2659 int 2660 t1394_alloc_isoch_dma(t1394_handle_t t1394_hdl, 2661 id1394_isoch_dmainfo_t *idi, uint_t flags, 2662 t1394_isoch_dma_handle_t *t1394_idma_hdl, int *result) 2663 { 2664 s1394_hal_t *hal; 2665 int ret; 2666 2667 ASSERT(t1394_hdl != NULL); 2668 ASSERT(idi != NULL); 2669 ASSERT(t1394_idma_hdl != NULL); 2670 2671 /* Find the HAL this target resides on */ 2672 hal = ((s1394_target_t *)t1394_hdl)->on_hal; 2673 2674 /* Sanity check dma options. If talk enabled, listen should be off */ 2675 if ((idi->idma_options & ID1394_TALK) && 2676 (idi->idma_options != ID1394_TALK)) { 2677 *result = T1394_EIDMA_CONFLICT; 2678 return (DDI_FAILURE); 2679 } 2680 2681 /* Only one listen mode allowed */ 2682 if ((idi->idma_options & ID1394_LISTEN_PKT_MODE) && 2683 (idi->idma_options & ID1394_LISTEN_BUF_MODE)) { 2684 *result = T1394_EIDMA_CONFLICT; 2685 return (DDI_FAILURE); 2686 } 2687 2688 /* Have HAL alloc a resource and compile ixl */ 2689 ret = HAL_CALL(hal).alloc_isoch_dma(hal->halinfo.hal_private, idi, 2690 (void **)t1394_idma_hdl, result); 2691 2692 if (ret != DDI_SUCCESS) { 2693 if (*result == IXL1394_ENO_DMA_RESRCS) { 2694 *result = T1394_EIDMA_NO_RESRCS; 2695 } 2696 } 2697 2698 return (ret); 2699 } 2700 2701 /* 2702 * Function: t1394_free_isoch_dma() 2703 * Input(s): t1394_hdl The target "handle" returned by 2704 * t1394_attach() 2705 * flags The flags parameter is unused (for now) 2706 * t1394_idma_hdl The IDMA "handle" returned by 2707 * t1394_alloc_isoch_dma() 2708 * 2709 * Output(s): None 2710 * 2711 * Description: t1394_free_isoch_dma() is used to free all DMA resources 2712 * allocated for the isoch stream associated with t1394_idma_hdl. 2713 */ 2714 /* ARGSUSED */ 2715 void 2716 t1394_free_isoch_dma(t1394_handle_t t1394_hdl, uint_t flags, 2717 t1394_isoch_dma_handle_t *t1394_idma_hdl) 2718 { 2719 s1394_hal_t *hal; 2720 2721 ASSERT(t1394_hdl != NULL); 2722 ASSERT(*t1394_idma_hdl != NULL); 2723 2724 /* Find the HAL this target resides on */ 2725 hal = ((s1394_target_t *)t1394_hdl)->on_hal; 2726 2727 /* Tell HAL to release local isoch dma resources */ 2728 HAL_CALL(hal).free_isoch_dma(hal->halinfo.hal_private, *t1394_idma_hdl); 2729 2730 /* Null out isoch handle */ 2731 *t1394_idma_hdl = NULL; 2732 } 2733 2734 /* 2735 * Function: t1394_start_isoch_dma() 2736 * Input(s): t1394_hdl The target "handle" returned by 2737 * t1394_attach() 2738 * t1394_idma_hdl The IDMA "handle" returned by 2739 * t1394_alloc_isoch_dma() 2740 * idma_ctrlinfo This structure contains control args 2741 * used when starting isoch DMA for 2742 * the allocated resource 2743 * flags One flag defined - ID1394_START_ON_CYCLE 2744 * 2745 * Output(s): result Used to pass more specific info back 2746 * to target 2747 * 2748 * Description: t1394_start_isoch_dma() is used to start DMA for the isoch 2749 * stream associated with t1394_idma_hdl. 2750 */ 2751 /* ARGSUSED */ 2752 int 2753 t1394_start_isoch_dma(t1394_handle_t t1394_hdl, 2754 t1394_isoch_dma_handle_t t1394_idma_hdl, 2755 id1394_isoch_dma_ctrlinfo_t *idma_ctrlinfo, uint_t flags, 2756 int *result) 2757 { 2758 s1394_hal_t *hal; 2759 int ret; 2760 2761 ASSERT(t1394_hdl != NULL); 2762 ASSERT(t1394_idma_hdl != NULL); 2763 ASSERT(idma_ctrlinfo != NULL); 2764 2765 /* Find the HAL this target resides on */ 2766 hal = ((s1394_target_t *)t1394_hdl)->on_hal; 2767 2768 ret = HAL_CALL(hal).start_isoch_dma(hal->halinfo.hal_private, 2769 (void *)t1394_idma_hdl, idma_ctrlinfo, flags, result); 2770 2771 return (ret); 2772 } 2773 2774 /* 2775 * Function: t1394_stop_isoch_dma() 2776 * Input(s): t1394_hdl The target "handle" returned by 2777 * t1394_attach() 2778 * t1394_idma_hdl The IDMA "handle" returned by 2779 * t1394_alloc_isoch_dma() 2780 * flags The flags parameter is unused (for now) 2781 * 2782 * Output(s): None 2783 * 2784 * Description: t1394_stop_isoch_dma() is used to stop DMA for the isoch 2785 * stream associated with t1394_idma_hdl. 2786 */ 2787 /* ARGSUSED */ 2788 void 2789 t1394_stop_isoch_dma(t1394_handle_t t1394_hdl, 2790 t1394_isoch_dma_handle_t t1394_idma_hdl, uint_t flags) 2791 { 2792 s1394_hal_t *hal; 2793 int result; 2794 2795 ASSERT(t1394_hdl != NULL); 2796 ASSERT(t1394_idma_hdl != NULL); 2797 2798 /* Find the HAL this target resides on */ 2799 hal = ((s1394_target_t *)t1394_hdl)->on_hal; 2800 2801 HAL_CALL(hal).stop_isoch_dma(hal->halinfo.hal_private, 2802 (void *)t1394_idma_hdl, &result); 2803 } 2804 2805 /* 2806 * Function: t1394_update_isoch_dma() 2807 * Input(s): t1394_hdl The target "handle" returned by 2808 * t1394_attach() 2809 * t1394_idma_hdl The IDMA "handle" returned by 2810 * t1394_alloc_isoch_dma() 2811 * idma_updateinfo This structure contains ixl command args 2812 * used when updating args in an 2813 * existing list of ixl commands with 2814 * args in a new list of ixl commands. 2815 * flags The flags parameter is unused (for now) 2816 * 2817 * Output(s): result Used to pass more specific info back 2818 * to target 2819 * 2820 * Description: t1394_update_isoch_dma() is used to alter an IXL program that 2821 * has already been built (compiled) by t1394_alloc_isoch_dma(). 2822 */ 2823 /* ARGSUSED */ 2824 int 2825 t1394_update_isoch_dma(t1394_handle_t t1394_hdl, 2826 t1394_isoch_dma_handle_t t1394_idma_hdl, 2827 id1394_isoch_dma_updateinfo_t *idma_updateinfo, uint_t flags, 2828 int *result) 2829 { 2830 s1394_hal_t *hal; 2831 int ret; 2832 2833 ASSERT(t1394_hdl != NULL); 2834 ASSERT(t1394_idma_hdl != NULL); 2835 ASSERT(idma_updateinfo != NULL); 2836 2837 /* Find the HAL this target resides on */ 2838 hal = ((s1394_target_t *)t1394_hdl)->on_hal; 2839 2840 ret = HAL_CALL(hal).update_isoch_dma(hal->halinfo.hal_private, 2841 (void *)t1394_idma_hdl, idma_updateinfo, flags, result); 2842 2843 return (ret); 2844 } 2845 2846 /* 2847 * Function: t1394_initiate_bus_reset() 2848 * Input(s): t1394_hdl The target "handle" returned by 2849 * t1394_attach() 2850 * flags The flags parameter is unused (for now) 2851 * 2852 * Output(s): None 2853 * 2854 * Description: t1394_initiate_bus_reset() determines whether the local 2855 * device has a P1394A PHY and will support the arbitrated 2856 * short bus reset. If not, it will initiate a normal bus reset. 2857 */ 2858 /* ARGSUSED */ 2859 void 2860 t1394_initiate_bus_reset(t1394_handle_t t1394_hdl, uint_t flags) 2861 { 2862 s1394_hal_t *hal; 2863 2864 ASSERT(t1394_hdl != NULL); 2865 2866 /* Find the HAL this target resides on */ 2867 hal = ((s1394_target_t *)t1394_hdl)->on_hal; 2868 2869 /* Reset the bus */ 2870 if (hal->halinfo.phy == H1394_PHY_1394A) { 2871 (void) HAL_CALL(hal).short_bus_reset(hal->halinfo.hal_private); 2872 } else { 2873 (void) HAL_CALL(hal).bus_reset(hal->halinfo.hal_private); 2874 } 2875 } 2876 2877 /* 2878 * Function: t1394_get_topology_map() 2879 * Input(s): t1394_hdl The target "handle" returned by 2880 * t1394_attach() 2881 * bus_generation The current generation 2882 * tm_length The size of the tm_buffer given 2883 * flags The flags parameter is unused (for now) 2884 * 2885 * Output(s): tm_buffer Filled in by the 1394 Software Framework 2886 * with the contents of the local 2887 * TOPOLOGY_MAP 2888 * 2889 * Description: t1394_get_topology_map() returns the 1394 TOPLOGY_MAP. See 2890 * IEEE 1394-1995 Section 8.2.3.4.1 for format information. This 2891 * call can fail if there is a generation mismatch or the 2892 * tm_buffer is too small to hold the TOPOLOGY_MAP. 2893 */ 2894 /* ARGSUSED */ 2895 int 2896 t1394_get_topology_map(t1394_handle_t t1394_hdl, uint_t bus_generation, 2897 size_t tm_length, uint_t flags, uint32_t *tm_buffer) 2898 { 2899 s1394_hal_t *hal; 2900 uint32_t *tm_ptr; 2901 uint_t length; 2902 2903 ASSERT(t1394_hdl != NULL); 2904 2905 /* Find the HAL this target resides on */ 2906 hal = ((s1394_target_t *)t1394_hdl)->on_hal; 2907 2908 /* Lock the topology tree */ 2909 mutex_enter(&hal->topology_tree_mutex); 2910 2911 /* Check the bus_generation for the Topology Map */ 2912 if (bus_generation != hal->generation_count) { 2913 /* Unlock the topology tree */ 2914 mutex_exit(&hal->topology_tree_mutex); 2915 return (DDI_FAILURE); 2916 } 2917 2918 tm_ptr = (uint32_t *)hal->CSR_topology_map; 2919 length = tm_ptr[0] >> 16; 2920 length = length * 4; /* Bytes instead of quadlets */ 2921 length = length + 4; /* don't forget the first quad */ 2922 2923 /* Check that the buffer is big enough */ 2924 if (length > (uint_t)tm_length) { 2925 /* Unlock the topology tree */ 2926 mutex_exit(&hal->topology_tree_mutex); 2927 return (DDI_FAILURE); 2928 } 2929 2930 /* Do the copy */ 2931 bcopy(tm_ptr, tm_buffer, length); 2932 2933 /* Unlock the topology tree */ 2934 mutex_exit(&hal->topology_tree_mutex); 2935 return (DDI_SUCCESS); 2936 } 2937 2938 /* 2939 * Function: t1394_CRC16() 2940 * Input(s): d The data to compute the CRC-16 for 2941 * crc_length The length into the data to compute for 2942 * flags The flags parameter is unused (for now) 2943 * 2944 * Output(s): CRC The CRC-16 computed for the length 2945 * of data specified 2946 * 2947 * Description: t1394_CRC16() implements ISO/IEC 13213:1994, ANSI/IEEE Std 2948 * 1212, 1994 - 8.1.5. 2949 */ 2950 /* ARGSUSED */ 2951 uint_t 2952 t1394_CRC16(uint32_t *d, size_t crc_length, uint_t flags) 2953 { 2954 /* Implements ISO/IEC 13213:1994, */ 2955 /* ANSI/IEEE Std 1212, 1994 - 8.1.5 */ 2956 uint_t ret; 2957 2958 ret = s1394_CRC16((uint_t *)d, (uint_t)crc_length); 2959 2960 return (ret); 2961 } 2962 2963 /* 2964 * Function: t1394_add_cfgrom_entry() 2965 * Input(s): t1394_hdl The target "handle" returned by 2966 * t1394_attach() 2967 * cfgrom_entryinfo This structure holds the cfgrom key, 2968 * buffer, and size 2969 * flags The flags parameter is unused (for now) 2970 * 2971 * Output(s): t1394_cfgrom_hdl The ConfigROM "handle" used in 2972 * t1394_rem_cfgrom_entry() 2973 * result Used to pass more specific info back 2974 * to target 2975 * 2976 * Description: t1394_add_cfgrom_entry() adds an entry to the local Config ROM, 2977 * updating the directory entries as necessary. This call could 2978 * fail because there is no room for the new entry in Config ROM 2979 * (T1394_ECFGROM_FULL), the key is invalid (T1394_EINVALID_PARAM), 2980 * or it was called in interrupt context (T1394_EINVALID_CONTEXT). 2981 */ 2982 /* ARGSUSED */ 2983 int 2984 t1394_add_cfgrom_entry(t1394_handle_t t1394_hdl, 2985 t1394_cfgrom_entryinfo_t *cfgrom_entryinfo, uint_t flags, 2986 t1394_cfgrom_handle_t *t1394_cfgrom_hdl, int *result) 2987 { 2988 s1394_hal_t *hal; 2989 s1394_target_t *target; 2990 int ret; 2991 uint_t key; 2992 uint_t size; 2993 uint32_t *buffer; 2994 2995 ASSERT(t1394_hdl != NULL); 2996 2997 target = (s1394_target_t *)t1394_hdl; 2998 2999 key = cfgrom_entryinfo->ce_key; 3000 buffer = cfgrom_entryinfo->ce_buffer; 3001 size = (uint_t)cfgrom_entryinfo->ce_size; 3002 3003 /* Check for a valid size */ 3004 if (size == 0) { 3005 *result = T1394_EINVALID_PARAM; 3006 return (DDI_FAILURE); 3007 } 3008 3009 /* Check for a valid key type */ 3010 if (((key << IEEE1212_KEY_VALUE_SHIFT) & IEEE1212_KEY_TYPE_MASK) == 0) { 3011 *result = T1394_EINVALID_PARAM; 3012 return (DDI_FAILURE); 3013 } 3014 3015 /* Find the HAL this target resides on */ 3016 hal = target->on_hal; 3017 3018 /* Is this on the interrupt stack? */ 3019 if (servicing_interrupt()) { 3020 *result = T1394_EINVALID_CONTEXT; 3021 return (DDI_FAILURE); 3022 } 3023 3024 /* Lock the Config ROM buffer */ 3025 mutex_enter(&hal->local_config_rom_mutex); 3026 3027 ret = s1394_add_config_rom_entry(hal, key, buffer, size, 3028 (void **)t1394_cfgrom_hdl, result); 3029 if (ret != DDI_SUCCESS) { 3030 if (*result == CMD1394_ERSRC_CONFLICT) 3031 *result = T1394_ECFGROM_FULL; 3032 mutex_exit(&hal->local_config_rom_mutex); 3033 3034 return (ret); 3035 } 3036 3037 /* Setup the timeout function */ 3038 if (hal->config_rom_timer_set == B_FALSE) { 3039 hal->config_rom_timer_set = B_TRUE; 3040 mutex_exit(&hal->local_config_rom_mutex); 3041 hal->config_rom_timer = 3042 timeout(s1394_update_config_rom_callback, hal, 3043 drv_usectohz(CONFIG_ROM_UPDATE_DELAY * 1000)); 3044 } else { 3045 mutex_exit(&hal->local_config_rom_mutex); 3046 } 3047 3048 return (ret); 3049 } 3050 3051 /* 3052 * Function: t1394_rem_cfgrom_entry() 3053 * Input(s): t1394_hdl The target "handle" returned by 3054 * t1394_attach() 3055 * flags The flags parameter is unused (for now) 3056 * t1394_cfgrom_hdl The ConfigROM "handle" returned by 3057 * t1394_add_cfgrom_entry() 3058 * 3059 * Output(s): result Used to pass more specific info back 3060 * to target 3061 * 3062 * Description: t1394_rem_cfgrom_entry() is used to remove a previously added 3063 * Config ROM entry (indicated by t1394_cfgrom_hdl). 3064 */ 3065 /* ARGSUSED */ 3066 int 3067 t1394_rem_cfgrom_entry(t1394_handle_t t1394_hdl, uint_t flags, 3068 t1394_cfgrom_handle_t *t1394_cfgrom_hdl, int *result) 3069 { 3070 s1394_hal_t *hal; 3071 s1394_target_t *target; 3072 int ret; 3073 3074 ASSERT(t1394_hdl != NULL); 3075 3076 target = (s1394_target_t *)t1394_hdl; 3077 3078 /* Find the HAL this target resides on */ 3079 hal = target->on_hal; 3080 3081 /* Is this on the interrupt stack? */ 3082 if (servicing_interrupt()) { 3083 *result = T1394_EINVALID_CONTEXT; 3084 return (DDI_FAILURE); 3085 } 3086 3087 /* Lock the Config ROM buffer */ 3088 mutex_enter(&hal->local_config_rom_mutex); 3089 3090 ret = s1394_remove_config_rom_entry(hal, (void **)t1394_cfgrom_hdl, 3091 result); 3092 if (ret != DDI_SUCCESS) { 3093 mutex_exit(&hal->local_config_rom_mutex); 3094 return (ret); 3095 } 3096 3097 /* Setup the timeout function */ 3098 if (hal->config_rom_timer_set == B_FALSE) { 3099 hal->config_rom_timer_set = B_TRUE; 3100 mutex_exit(&hal->local_config_rom_mutex); 3101 hal->config_rom_timer = 3102 timeout(s1394_update_config_rom_callback, hal, 3103 drv_usectohz(CONFIG_ROM_UPDATE_DELAY * 1000)); 3104 } else { 3105 mutex_exit(&hal->local_config_rom_mutex); 3106 } 3107 3108 return (ret); 3109 } 3110 3111 /* 3112 * Function: t1394_get_targetinfo() 3113 * Input(s): t1394_hdl The target "handle" returned by 3114 * t1394_attach() 3115 * bus_generation The current generation 3116 * flags The flags parameter is unused (for now) 3117 * 3118 * Output(s): targetinfo Structure containing max_payload, 3119 * max_speed, and target node ID. 3120 * 3121 * Description: t1394_get_targetinfo() is used to retrieve information specific 3122 * to a target device. It will fail if the generation given 3123 * does not match the current generation. 3124 */ 3125 /* ARGSUSED */ 3126 int 3127 t1394_get_targetinfo(t1394_handle_t t1394_hdl, uint_t bus_generation, 3128 uint_t flags, t1394_targetinfo_t *targetinfo) 3129 { 3130 s1394_hal_t *hal; 3131 s1394_target_t *target; 3132 uint_t dev; 3133 uint_t curr; 3134 uint_t from_node; 3135 uint_t to_node; 3136 3137 ASSERT(t1394_hdl != NULL); 3138 3139 /* Find the HAL this target resides on */ 3140 hal = ((s1394_target_t *)t1394_hdl)->on_hal; 3141 3142 target = (s1394_target_t *)t1394_hdl; 3143 3144 /* Lock the topology tree */ 3145 mutex_enter(&hal->topology_tree_mutex); 3146 3147 /* Check the bus_generation */ 3148 if (bus_generation != hal->generation_count) { 3149 /* Unlock the topology tree */ 3150 mutex_exit(&hal->topology_tree_mutex); 3151 return (DDI_FAILURE); 3152 } 3153 3154 rw_enter(&hal->target_list_rwlock, RW_READER); 3155 /* 3156 * If there is no node, report T1394_INVALID_NODEID for target_nodeID; 3157 * current_max_speed and current_max_payload are undefined for this 3158 * case. 3159 */ 3160 if (((target->target_state & S1394_TARG_GONE) != 0) || 3161 (target->on_node == NULL)) { 3162 targetinfo->target_nodeID = T1394_INVALID_NODEID; 3163 } else { 3164 targetinfo->target_nodeID = 3165 (target->on_hal->node_id & IEEE1394_BUS_NUM_MASK) | 3166 target->on_node->node_num; 3167 3168 from_node = (target->on_hal->node_id) & IEEE1394_NODE_NUM_MASK; 3169 to_node = target->on_node->node_num; 3170 3171 targetinfo->current_max_speed = (uint_t)s1394_speed_map_get( 3172 hal, from_node, to_node); 3173 3174 /* Get current_max_payload */ 3175 s1394_get_maxpayload(target, &dev, &curr); 3176 targetinfo->current_max_payload = curr; 3177 } 3178 3179 rw_exit(&hal->target_list_rwlock); 3180 /* Unlock the topology tree */ 3181 mutex_exit(&hal->topology_tree_mutex); 3182 return (DDI_SUCCESS); 3183 } 3184