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