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