bmake-ify mega_sas
[unleashed.git] / usr / src / uts / common / io / 1394 / t1394.c
blobb5e4817cfd9b2ed369ece5010f9b90df1ccdd121
1 /*
2 * CDDL HEADER START
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.
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.
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]
19 * CDDL HEADER END
22 * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
27 * t1394.c
28 * 1394 Target Driver Interface
29 * This file contains all of the 1394 Software Framework routines called
30 * by target drivers
33 #include <sys/sysmacros.h>
34 #include <sys/conf.h>
35 #include <sys/ddi.h>
36 #include <sys/sunddi.h>
37 #include <sys/types.h>
38 #include <sys/kmem.h>
39 #include <sys/disp.h>
40 #include <sys/tnf_probe.h>
42 #include <sys/1394/t1394.h>
43 #include <sys/1394/s1394.h>
44 #include <sys/1394/h1394.h>
45 #include <sys/1394/ieee1394.h>
47 static int s1394_allow_detach = 0;
50 * Function: t1394_attach()
51 * Input(s): dip The dip given to the target driver
52 * in it's attach() routine
53 * version The version of the target driver -
54 * T1394_VERSION_V1
55 * flags The flags parameter is unused (for now)
57 * Output(s): attachinfo Used to pass info back to target,
58 * including bus generation, local
59 * node ID, dma attribute, etc.
60 * t1394_hdl The target "handle" to be used for
61 * all subsequent calls into the
62 * 1394 Software Framework
64 * Description: t1394_attach() registers the target (based on its dip) with
65 * the 1394 Software Framework. It returns the bus_generation,
66 * local_nodeID, iblock_cookie and other useful information to
67 * the target, as well as a handle (t1394_hdl) that will be used
68 * in all subsequent calls into this framework.
70 /* ARGSUSED */
71 int
72 t1394_attach(dev_info_t *dip, int version, uint_t flags,
73 t1394_attachinfo_t *attachinfo, t1394_handle_t *t1394_hdl)
75 s1394_hal_t *hal;
76 s1394_target_t *target;
77 uint_t dev;
78 uint_t curr;
79 uint_t unit_dir;
80 int hp_node = 0;
82 ASSERT(t1394_hdl != NULL);
83 ASSERT(attachinfo != NULL);
85 *t1394_hdl = NULL;
87 if (version != T1394_VERSION_V1) {
88 return (DDI_FAILURE);
91 hal = s1394_dip_to_hal(ddi_get_parent(dip));
92 if (hal == NULL) {
93 return (DDI_FAILURE);
96 ASSERT(MUTEX_NOT_HELD(&hal->topology_tree_mutex));
98 hp_node = ddi_prop_exists(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS,
99 "hp-node");
101 /* Allocate space for s1394_target_t */
102 target = kmem_zalloc(sizeof (s1394_target_t), KM_SLEEP);
104 mutex_enter(&hal->topology_tree_mutex);
106 target->target_version = version;
108 /* Copy in the params */
109 target->target_dip = dip;
110 target->on_hal = hal;
112 /* Place the target on the appropriate node */
113 target->on_node = NULL;
115 rw_enter(&target->on_hal->target_list_rwlock, RW_WRITER);
116 if (hp_node != 0) {
117 s1394_add_target_to_node(target);
119 * on_node can be NULL if the node got unplugged
120 * while the target driver is in its attach routine.
122 if (target->on_node == NULL) {
123 s1394_remove_target_from_node(target);
124 rw_exit(&target->on_hal->target_list_rwlock);
125 mutex_exit(&hal->topology_tree_mutex);
126 kmem_free(target, sizeof (s1394_target_t));
127 return (DDI_FAILURE);
130 target->target_state = S1394_TARG_HP_NODE;
131 if (S1394_NODE_BUS_PWR_CONSUMER(target->on_node) == B_TRUE)
132 target->target_state |= S1394_TARG_BUS_PWR_CONSUMER;
135 /* Return the current generation */
136 attachinfo->localinfo.bus_generation = target->on_hal->generation_count;
138 /* Fill in hal node id */
139 attachinfo->localinfo.local_nodeID = target->on_hal->node_id;
141 /* Give the target driver the iblock_cookie */
142 attachinfo->iblock_cookie = target->on_hal->halinfo.hw_interrupt;
144 /* Give the target driver the attributes */
145 attachinfo->acc_attr = target->on_hal->halinfo.acc_attr;
146 attachinfo->dma_attr = target->on_hal->halinfo.dma_attr;
148 unit_dir = ddi_prop_get_int(DDI_DEV_T_ANY, dip,
149 DDI_PROP_DONTPASS, "unit-dir-offset", 0);
150 target->unit_dir = unit_dir;
152 /* By default, disable all physical AR requests */
153 target->physical_arreq_enabled = 0;
156 /* Get dev_max_payload & current_max_payload */
157 s1394_get_maxpayload(target, &dev, &curr);
158 target->dev_max_payload = dev;
159 target->current_max_payload = curr;
161 /* Add into linked list */
162 if ((target->on_hal->target_head == NULL) &&
163 (target->on_hal->target_tail == NULL)) {
164 target->on_hal->target_head = target;
165 target->on_hal->target_tail = target;
166 } else {
167 target->on_hal->target_tail->target_next = target;
168 target->target_prev = target->on_hal->target_tail;
169 target->on_hal->target_tail = target;
171 rw_exit(&target->on_hal->target_list_rwlock);
173 /* Fill in services layer private info */
174 *t1394_hdl = (t1394_handle_t)target;
176 mutex_exit(&hal->topology_tree_mutex);
178 return (DDI_SUCCESS);
182 * Function: t1394_detach()
183 * Input(s): t1394_hdl The target "handle" returned by
184 * t1394_attach()
185 * flags The flags parameter is unused (for now)
187 * Output(s): DDI_SUCCESS Target successfully detached
188 * DDI_FAILURE Target failed to detach
190 * Description: t1394_detach() unregisters the target from the 1394 Software
191 * Framework. t1394_detach() can fail if the target has any
192 * allocated commands that haven't been freed.
194 /* ARGSUSED */
196 t1394_detach(t1394_handle_t *t1394_hdl, uint_t flags)
198 s1394_target_t *target;
199 uint_t num_cmds;
201 ASSERT(t1394_hdl != NULL);
203 target = (s1394_target_t *)(*t1394_hdl);
205 ASSERT(target->on_hal);
207 mutex_enter(&target->on_hal->topology_tree_mutex);
208 rw_enter(&target->on_hal->target_list_rwlock, RW_WRITER);
210 /* How many cmds has this target allocated? */
211 num_cmds = target->target_num_cmds;
213 if (num_cmds != 0) {
214 rw_exit(&target->on_hal->target_list_rwlock);
215 mutex_exit(&target->on_hal->topology_tree_mutex);
216 return (DDI_FAILURE);
220 * Remove from linked lists. Topology tree is already locked
221 * so that the node won't go away while we are looking at it.
223 if ((target->on_hal->target_head == target) &&
224 (target->on_hal->target_tail == target)) {
225 target->on_hal->target_head = NULL;
226 target->on_hal->target_tail = NULL;
227 } else {
228 if (target->target_prev)
229 target->target_prev->target_next = target->target_next;
230 if (target->target_next)
231 target->target_next->target_prev = target->target_prev;
232 if (target->on_hal->target_head == target)
233 target->on_hal->target_head = target->target_next;
234 if (target->on_hal->target_tail == target)
235 target->on_hal->target_tail = target->target_prev;
238 s1394_remove_target_from_node(target);
239 rw_exit(&target->on_hal->target_list_rwlock);
241 mutex_exit(&target->on_hal->topology_tree_mutex);
243 /* Free memory */
244 kmem_free(target, sizeof (s1394_target_t));
246 *t1394_hdl = NULL;
248 return (DDI_SUCCESS);
252 * Function: t1394_alloc_cmd()
253 * Input(s): t1394_hdl The target "handle" returned by
254 * t1394_attach()
255 * flags The flags parameter is described below
257 * Output(s): cmdp Pointer to the newly allocated command
259 * Description: t1394_alloc_cmd() allocates a command for use with the
260 * t1394_read(), t1394_write(), or t1394_lock() interfaces
261 * of the 1394 Software Framework. By default, t1394_alloc_cmd()
262 * may sleep while allocating memory for the command structure.
263 * If this is undesirable, the target may set the
264 * T1394_ALLOC_CMD_NOSLEEP bit in the flags parameter. Also,
265 * this call may fail because a target driver has already
266 * allocated MAX_NUMBER_ALLOC_CMDS commands.
269 t1394_alloc_cmd(t1394_handle_t t1394_hdl, uint_t flags, cmd1394_cmd_t **cmdp)
271 s1394_hal_t *hal;
272 s1394_target_t *target;
273 s1394_cmd_priv_t *s_priv;
274 uint_t num_cmds;
276 ASSERT(t1394_hdl != NULL);
278 target = (s1394_target_t *)t1394_hdl;
280 /* Find the HAL this target resides on */
281 hal = target->on_hal;
283 rw_enter(&hal->target_list_rwlock, RW_WRITER);
285 /* How many cmds has this target allocated? */
286 num_cmds = target->target_num_cmds;
288 if (num_cmds >= MAX_NUMBER_ALLOC_CMDS) {
289 rw_exit(&hal->target_list_rwlock);
290 /* kstats - cmd alloc failures */
291 hal->hal_kstats->cmd_alloc_fail++;
292 return (DDI_FAILURE);
295 /* Increment the number of cmds this target has allocated? */
296 target->target_num_cmds = num_cmds + 1;
298 if (s1394_alloc_cmd(hal, flags, cmdp) != DDI_SUCCESS) {
299 target->target_num_cmds = num_cmds; /* Undo increment */
300 rw_exit(&hal->target_list_rwlock);
301 /* kstats - cmd alloc failures */
302 hal->hal_kstats->cmd_alloc_fail++;
303 return (DDI_FAILURE);
306 rw_exit(&hal->target_list_rwlock);
308 /* Get the Services Layer private area */
309 s_priv = S1394_GET_CMD_PRIV(*cmdp);
311 /* Initialize the command's blocking mutex */
312 mutex_init(&s_priv->blocking_mutex, NULL, MUTEX_DRIVER,
313 hal->halinfo.hw_interrupt);
315 /* Initialize the command's blocking condition variable */
316 cv_init(&s_priv->blocking_cv, NULL, CV_DRIVER, NULL);
318 return (DDI_SUCCESS);
322 * Function: t1394_free_cmd()
323 * Input(s): t1394_hdl The target "handle" returned by
324 * t1394_attach()
325 * flags The flags parameter is unused (for now)
326 * cmdp Pointer to the command to be freed
328 * Output(s): DDI_SUCCESS Target successfully freed command
329 * DDI_FAILURE Target failed to free command
331 * Description: t1394_free_cmd() attempts to free a command that has previously
332 * been allocated by the target driver. It is possible for
333 * t1394_free_cmd() to fail because the command is currently
334 * in-use by the 1394 Software Framework.
336 /* ARGSUSED */
338 t1394_free_cmd(t1394_handle_t t1394_hdl, uint_t flags, cmd1394_cmd_t **cmdp)
340 s1394_hal_t *hal;
341 s1394_target_t *target;
342 s1394_cmd_priv_t *s_priv;
343 uint_t num_cmds;
345 ASSERT(t1394_hdl != NULL);
347 target = (s1394_target_t *)t1394_hdl;
349 /* Find the HAL this target resides on */
350 hal = target->on_hal;
352 rw_enter(&hal->target_list_rwlock, RW_WRITER);
354 /* How many cmds has this target allocated? */
355 num_cmds = target->target_num_cmds;
357 if (num_cmds == 0) {
358 rw_exit(&hal->target_list_rwlock);
359 ASSERT(num_cmds != 0);
360 return (DDI_FAILURE);
363 /* Get the Services Layer private area */
364 s_priv = S1394_GET_CMD_PRIV(*cmdp);
366 /* Check that command isn't in use */
367 if (s_priv->cmd_in_use == B_TRUE) {
368 rw_exit(&hal->target_list_rwlock);
369 ASSERT(s_priv->cmd_in_use == B_FALSE);
370 return (DDI_FAILURE);
373 /* Decrement the number of cmds this target has allocated */
374 target->target_num_cmds--;
376 rw_exit(&hal->target_list_rwlock);
378 /* Destroy the command's blocking condition variable */
379 cv_destroy(&s_priv->blocking_cv);
381 /* Destroy the command's blocking mutex */
382 mutex_destroy(&s_priv->blocking_mutex);
384 kmem_cache_free(hal->hal_kmem_cachep, *cmdp);
386 /* Command pointer is set to NULL before returning */
387 *cmdp = NULL;
389 /* kstats - number of cmd frees */
390 hal->hal_kstats->cmd_free++;
392 return (DDI_SUCCESS);
396 * Function: t1394_read()
397 * Input(s): t1394_hdl The target "handle" returned by
398 * t1394_attach()
399 * cmd Pointer to the command to send
401 * Output(s): DDI_SUCCESS Target successful sent the command
402 * DDI_FAILURE Target failed to send command
404 * Description: t1394_read() attempts to send an asynchronous read request
405 * onto the 1394 bus.
408 t1394_read(t1394_handle_t t1394_hdl, cmd1394_cmd_t *cmd)
410 s1394_hal_t *to_hal;
411 s1394_target_t *target;
412 s1394_cmd_priv_t *s_priv;
413 s1394_hal_state_t state;
414 int ret;
415 int err;
417 ASSERT(t1394_hdl != NULL);
418 ASSERT(cmd != NULL);
420 /* Get the Services Layer private area */
421 s_priv = S1394_GET_CMD_PRIV(cmd);
423 /* Is this command currently in use? */
424 if (s_priv->cmd_in_use == B_TRUE) {
425 ASSERT(s_priv->cmd_in_use == B_FALSE);
426 return (DDI_FAILURE);
429 target = (s1394_target_t *)t1394_hdl;
431 /* Set-up the destination of the command */
432 to_hal = target->on_hal;
434 /* No status (default) */
435 cmd->cmd_result = CMD1394_NOSTATUS;
437 /* Check for proper command type */
438 if ((cmd->cmd_type != CMD1394_ASYNCH_RD_QUAD) &&
439 (cmd->cmd_type != CMD1394_ASYNCH_RD_BLOCK)) {
440 cmd->cmd_result = CMD1394_EINVALID_COMMAND;
441 return (DDI_FAILURE);
444 /* Is this a blocking command on interrupt stack? */
445 if ((cmd->cmd_options & CMD1394_BLOCKING) &&
446 (servicing_interrupt())) {
447 cmd->cmd_result = CMD1394_EINVALID_CONTEXT;
448 return (DDI_FAILURE);
451 mutex_enter(&to_hal->topology_tree_mutex);
452 state = to_hal->hal_state;
453 if (state != S1394_HAL_NORMAL) {
454 ret = s1394_HAL_asynch_error(to_hal, cmd, state);
455 if (ret != CMD1394_CMDSUCCESS) {
456 cmd->cmd_result = ret;
457 mutex_exit(&to_hal->topology_tree_mutex);
458 return (DDI_FAILURE);
462 ret = s1394_setup_asynch_command(to_hal, target, cmd,
463 S1394_CMD_READ, &err);
465 /* Command has now been put onto the queue! */
466 if (ret != DDI_SUCCESS) {
467 /* Copy error code into result */
468 cmd->cmd_result = err;
469 mutex_exit(&to_hal->topology_tree_mutex);
470 return (DDI_FAILURE);
474 * If this command was sent during a bus reset,
475 * then put it onto the pending Q.
477 if (state == S1394_HAL_RESET) {
478 /* Remove cmd from outstanding request Q */
479 s1394_remove_q_asynch_cmd(to_hal, cmd);
480 /* Are we on the bus reset event stack? */
481 if (s1394_on_br_thread(to_hal) == B_TRUE) {
482 /* Blocking commands are not allowed */
483 if (cmd->cmd_options & CMD1394_BLOCKING) {
484 mutex_exit(&to_hal->topology_tree_mutex);
485 s_priv->cmd_in_use = B_FALSE;
486 cmd->cmd_result = CMD1394_EINVALID_CONTEXT;
487 return (DDI_FAILURE);
491 s1394_pending_q_insert(to_hal, cmd, S1394_PENDING_Q_FRONT);
492 mutex_exit(&to_hal->topology_tree_mutex);
494 /* Block (if necessary) */
495 goto block_on_asynch_cmd;
497 mutex_exit(&to_hal->topology_tree_mutex);
499 /* Send the command out */
500 ret = s1394_xfer_asynch_command(to_hal, cmd, &err);
502 if (ret != DDI_SUCCESS) {
503 if (err == CMD1394_ESTALE_GENERATION) {
504 /* Remove cmd from outstanding request Q */
505 s1394_remove_q_asynch_cmd(to_hal, cmd);
506 s1394_pending_q_insert(to_hal, cmd,
507 S1394_PENDING_Q_FRONT);
509 /* Block (if necessary) */
510 goto block_on_asynch_cmd;
512 } else {
513 /* Remove cmd from outstanding request Q */
514 s1394_remove_q_asynch_cmd(to_hal, cmd);
516 s_priv->cmd_in_use = B_FALSE;
518 /* Copy error code into result */
519 cmd->cmd_result = err;
521 return (DDI_FAILURE);
523 } else {
524 /* Block (if necessary) */
525 goto block_on_asynch_cmd;
528 block_on_asynch_cmd:
529 s1394_block_on_asynch_cmd(cmd);
531 return (DDI_SUCCESS);
535 * Function: t1394_write()
536 * Input(s): t1394_hdl The target "handle" returned by
537 * t1394_attach()
538 * cmd Pointer to the command to send
540 * Output(s): DDI_SUCCESS Target successful sent the command
541 * DDI_FAILURE Target failed to send command
543 * Description: t1394_write() attempts to send an asynchronous write request
544 * onto the 1394 bus.
547 t1394_write(t1394_handle_t t1394_hdl, cmd1394_cmd_t *cmd)
549 s1394_hal_t *to_hal;
550 s1394_target_t *target;
551 s1394_cmd_priv_t *s_priv;
552 s1394_hal_state_t state;
553 int ret;
554 int err;
556 ASSERT(t1394_hdl != NULL);
557 ASSERT(cmd != NULL);
559 /* Get the Services Layer private area */
560 s_priv = S1394_GET_CMD_PRIV(cmd);
562 /* Is this command currently in use? */
563 if (s_priv->cmd_in_use == B_TRUE) {
564 ASSERT(s_priv->cmd_in_use == B_FALSE);
565 return (DDI_FAILURE);
568 target = (s1394_target_t *)t1394_hdl;
570 /* Set-up the destination of the command */
571 to_hal = target->on_hal;
573 /* Is this an FA request? */
574 if (s_priv->cmd_ext_type == S1394_CMD_EXT_FA) {
575 if (S1394_IS_CMD_FCP(s_priv) &&
576 (s1394_fcp_write_check_cmd(cmd) != DDI_SUCCESS)) {
577 return (DDI_FAILURE);
579 s1394_fa_convert_cmd(to_hal, cmd);
582 /* No status (default) */
583 cmd->cmd_result = CMD1394_NOSTATUS;
585 /* Check for proper command type */
586 if ((cmd->cmd_type != CMD1394_ASYNCH_WR_QUAD) &&
587 (cmd->cmd_type != CMD1394_ASYNCH_WR_BLOCK)) {
588 cmd->cmd_result = CMD1394_EINVALID_COMMAND;
589 s1394_fa_check_restore_cmd(to_hal, cmd);
590 return (DDI_FAILURE);
593 /* Is this a blocking command on interrupt stack? */
594 if ((cmd->cmd_options & CMD1394_BLOCKING) &&
595 (servicing_interrupt())) {
596 cmd->cmd_result = CMD1394_EINVALID_CONTEXT;
597 s1394_fa_check_restore_cmd(to_hal, cmd);
598 return (DDI_FAILURE);
601 mutex_enter(&to_hal->topology_tree_mutex);
602 state = to_hal->hal_state;
603 if (state != S1394_HAL_NORMAL) {
604 ret = s1394_HAL_asynch_error(to_hal, cmd, state);
605 if (ret != CMD1394_CMDSUCCESS) {
606 cmd->cmd_result = ret;
607 mutex_exit(&to_hal->topology_tree_mutex);
608 s1394_fa_check_restore_cmd(to_hal, cmd);
609 return (DDI_FAILURE);
613 ret = s1394_setup_asynch_command(to_hal, target, cmd,
614 S1394_CMD_WRITE, &err);
616 /* Command has now been put onto the queue! */
617 if (ret != DDI_SUCCESS) {
618 /* Copy error code into result */
619 cmd->cmd_result = err;
620 mutex_exit(&to_hal->topology_tree_mutex);
621 s1394_fa_check_restore_cmd(to_hal, cmd);
622 return (DDI_FAILURE);
626 * If this command was sent during a bus reset,
627 * then put it onto the pending Q.
629 if (state == S1394_HAL_RESET) {
630 /* Remove cmd from outstanding request Q */
631 s1394_remove_q_asynch_cmd(to_hal, cmd);
632 /* Are we on the bus reset event stack? */
633 if (s1394_on_br_thread(to_hal) == B_TRUE) {
634 /* Blocking commands are not allowed */
635 if (cmd->cmd_options & CMD1394_BLOCKING) {
636 mutex_exit(&to_hal->topology_tree_mutex);
637 s_priv->cmd_in_use = B_FALSE;
638 cmd->cmd_result = CMD1394_EINVALID_CONTEXT;
639 s1394_fa_check_restore_cmd(to_hal, cmd);
640 return (DDI_FAILURE);
644 s1394_pending_q_insert(to_hal, cmd, S1394_PENDING_Q_FRONT);
645 mutex_exit(&to_hal->topology_tree_mutex);
647 /* Block (if necessary) */
648 s1394_block_on_asynch_cmd(cmd);
650 return (DDI_SUCCESS);
652 mutex_exit(&to_hal->topology_tree_mutex);
654 /* Send the command out */
655 ret = s1394_xfer_asynch_command(to_hal, cmd, &err);
657 if (ret != DDI_SUCCESS) {
658 if (err == CMD1394_ESTALE_GENERATION) {
659 /* Remove cmd from outstanding request Q */
660 s1394_remove_q_asynch_cmd(to_hal, cmd);
661 s1394_pending_q_insert(to_hal, cmd,
662 S1394_PENDING_Q_FRONT);
664 /* Block (if necessary) */
665 s1394_block_on_asynch_cmd(cmd);
667 return (DDI_SUCCESS);
668 } else {
669 /* Remove cmd from outstanding request Q */
670 s1394_remove_q_asynch_cmd(to_hal, cmd);
672 s_priv->cmd_in_use = B_FALSE;
674 /* Copy error code into result */
675 cmd->cmd_result = err;
677 s1394_fa_check_restore_cmd(to_hal, cmd);
678 return (DDI_FAILURE);
680 } else {
681 /* Block (if necessary) */
682 s1394_block_on_asynch_cmd(cmd);
684 return (DDI_SUCCESS);
689 * Function: t1394_lock()
690 * Input(s): t1394_hdl The target "handle" returned by
691 * t1394_attach()
692 * cmd Pointer to the command to send
694 * Output(s): DDI_SUCCESS Target successful sent the command
695 * DDI_FAILURE Target failed to send command
697 * Description: t1394_lock() attempts to send an asynchronous lock request
698 * onto the 1394 bus.
701 t1394_lock(t1394_handle_t t1394_hdl, cmd1394_cmd_t *cmd)
703 s1394_hal_t *to_hal;
704 s1394_target_t *target;
705 s1394_cmd_priv_t *s_priv;
706 s1394_hal_state_t state;
707 cmd1394_lock_type_t lock_type;
708 uint_t num_retries;
709 int ret;
711 ASSERT(t1394_hdl != NULL);
712 ASSERT(cmd != NULL);
714 /* Get the Services Layer private area */
715 s_priv = S1394_GET_CMD_PRIV(cmd);
717 /* Is this command currently in use? */
718 if (s_priv->cmd_in_use == B_TRUE) {
719 ASSERT(s_priv->cmd_in_use == B_FALSE);
720 return (DDI_FAILURE);
723 target = (s1394_target_t *)t1394_hdl;
725 /* Set-up the destination of the command */
726 to_hal = target->on_hal;
728 mutex_enter(&to_hal->topology_tree_mutex);
729 state = to_hal->hal_state;
730 if (state != S1394_HAL_NORMAL) {
731 ret = s1394_HAL_asynch_error(to_hal, cmd, state);
732 if (ret != CMD1394_CMDSUCCESS) {
733 cmd->cmd_result = ret;
734 mutex_exit(&to_hal->topology_tree_mutex);
735 return (DDI_FAILURE);
738 mutex_exit(&to_hal->topology_tree_mutex);
740 /* Check for proper command type */
741 if ((cmd->cmd_type != CMD1394_ASYNCH_LOCK_32) &&
742 (cmd->cmd_type != CMD1394_ASYNCH_LOCK_64)) {
743 cmd->cmd_result = CMD1394_EINVALID_COMMAND;
744 return (DDI_FAILURE);
747 /* No status (default) */
748 cmd->cmd_result = CMD1394_NOSTATUS;
750 /* Is this a blocking command on interrupt stack? */
751 if ((cmd->cmd_options & CMD1394_BLOCKING) &&
752 (servicing_interrupt())) {
753 cmd->cmd_result = CMD1394_EINVALID_CONTEXT;
754 return (DDI_FAILURE);
757 if (cmd->cmd_type == CMD1394_ASYNCH_LOCK_32) {
758 lock_type = cmd->cmd_u.l32.lock_type;
759 num_retries = cmd->cmd_u.l32.num_retries;
760 } else { /* (cmd->cmd_type == CMD1394_ASYNCH_LOCK_64) */
761 lock_type = cmd->cmd_u.l64.lock_type;
762 num_retries = cmd->cmd_u.l64.num_retries;
765 /* Make sure num_retries is reasonable */
766 ASSERT(num_retries <= MAX_NUMBER_OF_LOCK_RETRIES);
768 switch (lock_type) {
769 case CMD1394_LOCK_MASK_SWAP:
770 case CMD1394_LOCK_FETCH_ADD:
771 case CMD1394_LOCK_LITTLE_ADD:
772 case CMD1394_LOCK_BOUNDED_ADD:
773 case CMD1394_LOCK_WRAP_ADD:
774 case CMD1394_LOCK_COMPARE_SWAP:
775 ret = s1394_compare_swap(to_hal, target, cmd);
776 break;
778 case CMD1394_LOCK_BIT_AND:
779 case CMD1394_LOCK_BIT_OR:
780 case CMD1394_LOCK_BIT_XOR:
781 case CMD1394_LOCK_INCREMENT:
782 case CMD1394_LOCK_DECREMENT:
783 case CMD1394_LOCK_ADD:
784 case CMD1394_LOCK_SUBTRACT:
785 case CMD1394_LOCK_THRESH_ADD:
786 case CMD1394_LOCK_THRESH_SUBTRACT:
787 case CMD1394_LOCK_CLIP_ADD:
788 case CMD1394_LOCK_CLIP_SUBTRACT:
789 ret = s1394_split_lock_req(to_hal, target, cmd);
790 break;
792 default:
793 cmd->cmd_result = CMD1394_EINVALID_COMMAND;
794 ret = DDI_FAILURE;
795 break;
798 return (ret);
802 * Function: t1394_alloc_addr()
803 * Input(s): t1394_hdl The target "handle" returned by
804 * t1394_attach()
805 * addr_allocp The structure used to specify the type,
806 * size, permissions, and callbacks
807 * (if any) for the requested block
808 * of 1394 address space
809 * flags The flags parameter is unused (for now)
811 * Output(s): result Used to pass more specific info back
812 * to target
814 * Description: t1394_alloc_addr() requests that part of the 1394 Address Space
815 * on the local node be set aside for this target driver, and
816 * associated with this address space should be some permissions
817 * and callbacks. If the request is unable to be fulfilled,
818 * t1394_alloc_addr() will return DDI_FAILURE and result will
819 * indicate the reason. T1394_EINVALID_PARAM indicates that the
820 * combination of flags given is invalid, and T1394_EALLOC_ADDR
821 * indicates that the requested type of address space is
822 * unavailable.
824 /* ARGSUSED */
826 t1394_alloc_addr(t1394_handle_t t1394_hdl, t1394_alloc_addr_t *addr_allocp,
827 uint_t flags, int *result)
829 s1394_hal_t *hal;
830 s1394_target_t *target;
831 uint64_t addr_lo;
832 uint64_t addr_hi;
833 int err;
835 ASSERT(t1394_hdl != NULL);
836 ASSERT(addr_allocp != NULL);
838 target = (s1394_target_t *)t1394_hdl;
840 /* Find the HAL this target resides on */
841 hal = target->on_hal;
843 /* Get the bounds of the request */
844 addr_lo = addr_allocp->aa_address;
845 addr_hi = addr_lo + addr_allocp->aa_length;
847 /* Check combination of flags */
848 if ((addr_allocp->aa_enable & T1394_ADDR_RDENBL) &&
849 (addr_allocp->aa_evts.recv_read_request == NULL) &&
850 (addr_allocp->aa_kmem_bufp == NULL)) {
851 if ((addr_allocp->aa_type != T1394_ADDR_FIXED) ||
852 (addr_lo < hal->physical_addr_lo) ||
853 (addr_hi > hal->physical_addr_hi)) {
856 * Reads are enabled, but target doesn't want to
857 * be notified and hasn't given backing store
859 *result = T1394_EINVALID_PARAM;
861 /* kstats - addr alloc failures */
862 hal->hal_kstats->addr_alloc_fail++;
863 return (DDI_FAILURE);
864 } else {
865 addr_allocp->aa_enable &= ~T1394_ADDR_RDENBL;
869 if ((addr_allocp->aa_enable & T1394_ADDR_WRENBL) &&
870 (addr_allocp->aa_evts.recv_write_request == NULL) &&
871 (addr_allocp->aa_kmem_bufp == NULL)) {
872 if ((addr_allocp->aa_type != T1394_ADDR_FIXED) ||
873 (addr_lo < hal->physical_addr_lo) ||
874 (addr_hi > hal->physical_addr_hi)) {
877 * Writes are enabled, but target doesn't want to
878 * be notified and hasn't given backing store
880 *result = T1394_EINVALID_PARAM;
882 /* kstats - addr alloc failures */
883 hal->hal_kstats->addr_alloc_fail++;
884 return (DDI_FAILURE);
885 } else {
886 addr_allocp->aa_enable &= ~T1394_ADDR_WRENBL;
890 if ((addr_allocp->aa_enable & T1394_ADDR_LKENBL) &&
891 (addr_allocp->aa_evts.recv_lock_request == NULL) &&
892 (addr_allocp->aa_kmem_bufp == NULL)) {
893 if ((addr_allocp->aa_type != T1394_ADDR_FIXED) ||
894 (addr_lo < hal->physical_addr_lo) ||
895 (addr_hi > hal->physical_addr_hi)) {
898 * Locks are enabled, but target doesn't want to
899 * be notified and hasn't given backing store
901 *result = T1394_EINVALID_PARAM;
903 /* kstats - addr alloc failures */
904 hal->hal_kstats->addr_alloc_fail++;
905 return (DDI_FAILURE);
906 } else {
907 addr_allocp->aa_enable &= ~T1394_ADDR_LKENBL;
911 /* If not T1394_ADDR_FIXED, then allocate a block */
912 if (addr_allocp->aa_type != T1394_ADDR_FIXED) {
913 err = s1394_request_addr_blk((s1394_hal_t *)target->on_hal,
914 addr_allocp);
915 if (err != DDI_SUCCESS) {
916 *result = T1394_EALLOC_ADDR;
917 /* kstats - addr alloc failures */
918 hal->hal_kstats->addr_alloc_fail++;
919 } else {
920 *result = T1394_NOERROR;
922 return (err);
923 } else {
924 err = s1394_claim_addr_blk((s1394_hal_t *)target->on_hal,
925 addr_allocp);
926 if (err != DDI_SUCCESS) {
927 *result = T1394_EALLOC_ADDR;
928 /* kstats - addr alloc failures */
929 hal->hal_kstats->addr_alloc_fail++;
930 } else {
931 *result = T1394_NOERROR;
932 /* If physical, update the AR request counter */
933 if ((addr_lo >= hal->physical_addr_lo) &&
934 (addr_hi <= hal->physical_addr_hi)) {
935 rw_enter(&hal->target_list_rwlock, RW_WRITER);
936 target->physical_arreq_enabled++;
937 rw_exit(&hal->target_list_rwlock);
939 s1394_physical_arreq_set_one(target);
942 return (err);
947 * Function: t1394_free_addr()
948 * Input(s): t1394_hdl The target "handle" returned by
949 * t1394_attach()
950 * addr_hdl The address "handle" returned by the
951 * the t1394_alloc_addr() routine
952 * flags The flags parameter is unused (for now)
954 * Output(s): DDI_SUCCESS Target successfully freed memory
955 * DDI_FAILURE Target failed to free the memory block
957 * Description: t1394_free_addr() attempts to free up memory that has been
958 * allocated by the target using t1394_alloc_addr().
960 /* ARGSUSED */
962 t1394_free_addr(t1394_handle_t t1394_hdl, t1394_addr_handle_t *addr_hdl,
963 uint_t flags)
965 s1394_addr_space_blk_t *curr_blk;
966 s1394_hal_t *hal;
967 s1394_target_t *target;
969 ASSERT(t1394_hdl != NULL);
970 ASSERT(addr_hdl != NULL);
972 target = (s1394_target_t *)t1394_hdl;
974 /* Find the HAL this target resides on */
975 hal = target->on_hal;
977 curr_blk = (s1394_addr_space_blk_t *)(*addr_hdl);
979 if (s1394_free_addr_blk(hal, curr_blk) != DDI_SUCCESS) {
980 return (DDI_FAILURE);
983 /* If physical, update the AR request counter */
984 if (curr_blk->addr_type == T1394_ADDR_FIXED) {
985 target->physical_arreq_enabled--;
986 s1394_physical_arreq_clear_one(target);
989 *addr_hdl = NULL;
991 /* kstats - number of addr frees */
992 hal->hal_kstats->addr_space_free++;
994 return (DDI_SUCCESS);
998 * Function: t1394_recv_request_done()
999 * Input(s): t1394_hdl The target "handle" returned by
1000 * t1394_attach()
1001 * resp Pointer to the command which the
1002 * target received in it's callback
1003 * flags The flags parameter is unused (for now)
1005 * Output(s): DDI_SUCCESS Target successfully returned command
1006 * to the 1394 Software Framework,
1007 * and, if necessary, sent response
1008 * DDI_FAILURE Target failed to return the command to
1009 * the 1394 Software Framework
1011 * Description: t1394_recv_request_done() takes the command that is given and
1012 * determines whether that command requires a response to be
1013 * sent on the 1394 bus. If it is necessary and it's response
1014 * code (cmd_result) has been set appropriately, then a response
1015 * will be sent. If no response is necessary (broadcast or
1016 * posted write), then the command resources are reclaimed.
1018 /* ARGSUSED */
1020 t1394_recv_request_done(t1394_handle_t t1394_hdl, cmd1394_cmd_t *resp,
1021 uint_t flags)
1023 s1394_hal_t *hal;
1024 s1394_cmd_priv_t *s_priv;
1025 h1394_cmd_priv_t *h_priv;
1026 mblk_t *curr_blk;
1027 size_t msgb_len;
1028 size_t size;
1029 int ret;
1030 boolean_t response = B_TRUE;
1031 boolean_t posted_write = B_FALSE;
1032 boolean_t write_cmd = B_FALSE;
1033 boolean_t mblk_too_small;
1035 ASSERT(t1394_hdl != NULL);
1036 ASSERT(resp != NULL);
1038 /* Find the HAL this target resides on */
1039 hal = ((s1394_target_t *)t1394_hdl)->on_hal;
1041 /* Get the Services Layer private area */
1042 s_priv = S1394_GET_CMD_PRIV(resp);
1044 /* Get a pointer to the HAL private struct */
1045 h_priv = (h1394_cmd_priv_t *)&s_priv->hal_cmd_private;
1047 /* Is this an FA request? */
1048 if (s_priv->cmd_ext_type == S1394_CMD_EXT_FA) {
1049 s1394_fa_convert_cmd(hal, resp);
1052 /* Is this a write request? */
1053 if ((resp->cmd_type == CMD1394_ASYNCH_WR_QUAD) ||
1054 (resp->cmd_type == CMD1394_ASYNCH_WR_BLOCK)) {
1055 write_cmd = B_TRUE;
1056 /* Is this a posted write request? */
1057 posted_write = s_priv->posted_write;
1060 /* If broadcast or posted write cmd, don't send response */
1061 if ((resp->broadcast == 1) ||
1062 ((write_cmd == B_TRUE) && (posted_write == B_TRUE)))
1063 response = B_FALSE;
1065 if (response == B_FALSE) {
1066 if ((write_cmd == B_TRUE) && (posted_write == B_TRUE)) {
1067 /* kstats - Posted Write error */
1068 hal->hal_kstats->arreq_posted_write_error++;
1071 /* Free the command - Pass it back to the HAL */
1072 HAL_CALL(hal).response_complete(hal->halinfo.hal_private, resp,
1073 h_priv);
1074 return (DDI_SUCCESS);
1077 ASSERT(response == B_TRUE);
1079 /* Verify valid response code */
1080 switch (resp->cmd_result) {
1081 case IEEE1394_RESP_COMPLETE:
1082 /* Is the mblk_t too small? */
1083 if (resp->cmd_type == CMD1394_ASYNCH_RD_BLOCK) {
1084 curr_blk = resp->cmd_u.b.data_block;
1085 size = resp->cmd_u.b.blk_length;
1086 msgb_len = 0;
1087 mblk_too_small = B_TRUE;
1089 if (curr_blk == NULL) {
1091 * Free the command - Pass it back
1092 * to the HAL
1094 HAL_CALL(hal).response_complete(
1095 hal->halinfo.hal_private, resp, h_priv);
1096 ASSERT(curr_blk != NULL);
1097 return (DDI_FAILURE);
1100 while (curr_blk != NULL) {
1101 msgb_len +=
1102 (curr_blk->b_wptr - curr_blk->b_rptr);
1104 if (msgb_len >= size) {
1105 mblk_too_small = B_FALSE;
1106 break;
1108 curr_blk = curr_blk->b_cont;
1111 if (mblk_too_small == B_TRUE) {
1113 * Free the command - Pass it back
1114 * to the HAL
1116 HAL_CALL(hal).response_complete(
1117 hal->halinfo.hal_private, resp, h_priv);
1118 ASSERT(mblk_too_small != B_TRUE);
1119 return (DDI_FAILURE);
1122 /* FALLTHROUGH */
1123 case IEEE1394_RESP_CONFLICT_ERROR:
1124 case IEEE1394_RESP_DATA_ERROR:
1125 case IEEE1394_RESP_TYPE_ERROR:
1126 case IEEE1394_RESP_ADDRESS_ERROR:
1127 ret = s1394_send_response(hal, resp);
1128 return (ret);
1130 default:
1131 return (DDI_FAILURE);
1137 * Function: t1394_fcp_register_controller()
1138 * Input(s): t1394_hdl The target "handle" returned by
1139 * t1394_attach()
1140 * evts The structure in which the target
1141 * specifies its callback routines
1143 * flags The flags parameter is unused (for now)
1145 * Output(s): DDI_SUCCESS Successfully registered.
1147 * DDI_FAILURE Not registered due to failure.
1149 * Description: Used to register the target within the Framework as an FCP
1150 * controller.
1152 /* ARGSUSED */
1154 t1394_fcp_register_controller(t1394_handle_t t1394_hdl, t1394_fcp_evts_t *evts,
1155 uint_t flags)
1157 int result;
1159 ASSERT(t1394_hdl != NULL);
1161 result = s1394_fcp_register_ctl((s1394_target_t *)t1394_hdl, evts);
1163 return (result);
1167 * Function: t1394_fcp_unregister_controller()
1168 * Input(s): t1394_hdl The target "handle" returned by
1169 * t1394_attach()
1171 * Output(s): DDI_SUCCESS Successfully unregistered.
1173 * DDI_FAILURE Not unregistered due to failure.
1175 * Description: Used to unregister the target within the Framework as an FCP
1176 * controller.
1179 t1394_fcp_unregister_controller(t1394_handle_t t1394_hdl)
1181 int result;
1183 ASSERT(t1394_hdl != NULL);
1185 result = s1394_fcp_unregister_ctl((s1394_target_t *)t1394_hdl);
1187 return (result);
1191 * Function: t1394_fcp_register_target()
1192 * Input(s): t1394_hdl The target "handle" returned by
1193 * t1394_attach()
1194 * evts The structure in which the target
1195 * specifies its callback routines
1197 * flags The flags parameter is unused (for now)
1199 * Output(s): DDI_SUCCESS Successfully registered.
1201 * DDI_FAILURE Not registered due to failure.
1203 * Description: Used to register the target within the Framework as an FCP
1204 * target.
1206 /* ARGSUSED */
1208 t1394_fcp_register_target(t1394_handle_t t1394_hdl, t1394_fcp_evts_t *evts,
1209 uint_t flags)
1211 int result;
1213 ASSERT(t1394_hdl != NULL);
1215 result = s1394_fcp_register_tgt((s1394_target_t *)t1394_hdl, evts);
1217 return (result);
1221 * Function: t1394_fcp_unregister_target()
1222 * Input(s): t1394_hdl The target "handle" returned by
1223 * t1394_attach()
1225 * Output(s): DDI_SUCCESS Successfully unregistered.
1227 * DDI_FAILURE Not unregistered due to failure.
1229 * Description: Used to unregister the target within the Framework as an FCP
1230 * target.
1233 t1394_fcp_unregister_target(t1394_handle_t t1394_hdl)
1235 int result;
1237 ASSERT(t1394_hdl != NULL);
1239 result = s1394_fcp_unregister_tgt((s1394_target_t *)t1394_hdl);
1241 return (result);
1245 * Function: t1394_cmp_register()
1246 * Input(s): t1394_hdl The target "handle" returned by
1247 * t1394_attach()
1248 * evts The structure in which the target
1249 * specifies its callback routines
1251 * Output(s): DDI_SUCCESS Successfully registered.
1253 * DDI_FAILURE Not registered due to failure.
1255 * Description: Used to register the target within the Framework as a CMP
1256 * device.
1258 /* ARGSUSED */
1260 t1394_cmp_register(t1394_handle_t t1394_hdl, t1394_cmp_evts_t *evts,
1261 uint_t flags)
1263 int result;
1265 ASSERT(t1394_hdl != NULL);
1267 result = s1394_cmp_register((s1394_target_t *)t1394_hdl, evts);
1269 return (result);
1273 * Function: t1394_cmp_unregister()
1274 * Input(s): t1394_hdl The target "handle" returned by
1275 * t1394_attach()
1276 * evts The structure in which the target
1277 * specifies its callback routines
1279 * Output(s): DDI_SUCCESS Successfully registered.
1281 * DDI_FAILURE Not registered due to failure.
1283 * Description: Used to unregister the target within the Framework as a CMP
1284 * device.
1287 t1394_cmp_unregister(t1394_handle_t t1394_hdl)
1289 int result;
1291 ASSERT(t1394_hdl != NULL);
1293 result = s1394_cmp_unregister((s1394_target_t *)t1394_hdl);
1295 return (result);
1299 * Function: t1394_cmp_read()
1300 * Input(s): t1394_hdl The target "handle" returned by
1301 * t1394_attach()
1302 * reg Register type.
1303 * valp Returned register value.
1305 * Output(s): DDI_SUCCESS Successfully registered.
1307 * DDI_FAILURE Not registered due to failure.
1309 * Description: Used to read a CMP register value.
1312 t1394_cmp_read(t1394_handle_t t1394_hdl, t1394_cmp_reg_t reg, uint32_t *valp)
1314 int result;
1316 ASSERT(t1394_hdl != NULL);
1318 result = s1394_cmp_read((s1394_target_t *)t1394_hdl, reg, valp);
1320 return (result);
1324 * Function: t1394_cmp_cas()
1325 * Input(s): t1394_hdl The target "handle" returned by
1326 * t1394_attach()
1327 * reg Register type.
1328 * arg_val Compare argument.
1329 * new_val New register value.
1330 * old_valp Returned original register value.
1332 * Output(s): DDI_SUCCESS Successfully registered.
1334 * DDI_FAILURE Not registered due to failure.
1336 * Description: Used to compare-swap a CMP register value.
1339 t1394_cmp_cas(t1394_handle_t t1394_hdl, t1394_cmp_reg_t reg, uint32_t arg_val,
1340 uint32_t new_val, uint32_t *old_valp)
1342 int result;
1344 ASSERT(t1394_hdl != NULL);
1346 result = s1394_cmp_cas((s1394_target_t *)t1394_hdl, reg, arg_val,
1347 new_val, old_valp);
1349 return (result);
1353 * Function: t1394_alloc_isoch_single()
1354 * Input(s): t1394_hdl The target "handle" returned by
1355 * t1394_attach()
1356 * sii The structure used to set up the
1357 * overall characteristics of the
1358 * isochronous stream
1359 * flags The flags parameter is unused (for now)
1361 * Output(s): setup_args Contains the channel number that was
1362 * allocated
1363 * t1394_single_hdl This in the isoch "handle" used in
1364 * t1394_free_isoch_single()
1365 * result Used to pass more specific info back
1366 * to target
1368 * Description: t1394_alloc_isoch_single() is used to direct the 1394 Software
1369 * Framework to allocate an isochronous channel and bandwidth
1370 * from the Isochronous Resource Manager (IRM). If a bus reset
1371 * occurs, the 1394 Software Framework attempts to reallocate the
1372 * same resources, calling the rsrc_fail_target() callback if
1373 * it is unsuccessful.
1375 /* ARGSUSED */
1377 t1394_alloc_isoch_single(t1394_handle_t t1394_hdl,
1378 t1394_isoch_singleinfo_t *sii, uint_t flags,
1379 t1394_isoch_single_out_t *output_args,
1380 t1394_isoch_single_handle_t *t1394_single_hdl, int *result)
1382 s1394_hal_t *hal;
1383 s1394_isoch_cec_t *cec_new;
1384 t1394_join_isochinfo_t jii;
1385 int ret;
1386 int err;
1388 ASSERT(t1394_hdl != NULL);
1389 ASSERT(t1394_single_hdl != NULL);
1390 ASSERT(sii != NULL);
1392 hal = ((s1394_target_t *)t1394_hdl)->on_hal;
1394 /* Check for invalid channel_mask */
1395 if (sii->si_channel_mask == 0) {
1396 return (DDI_FAILURE);
1399 /* Check for invalid bandwidth */
1400 if ((sii->si_bandwidth <= IEEE1394_BANDWIDTH_MIN) ||
1401 (sii->si_bandwidth > IEEE1394_BANDWIDTH_MAX)) {
1402 return (DDI_FAILURE);
1405 /* Verify that rsrc_fail_target() callback is non-NULL */
1406 if (sii->rsrc_fail_target == NULL) {
1407 return (DDI_FAILURE);
1411 * Allocate an Isoch CEC of type S1394_SINGLE
1414 /* Allocate the Isoch CEC structure */
1415 cec_new = kmem_zalloc(sizeof (s1394_isoch_cec_t), KM_SLEEP);
1417 /* Initialize the structure type */
1418 cec_new->cec_type = S1394_SINGLE;
1420 /* Create the mutex and "in_callbacks" cv */
1421 mutex_init(&cec_new->isoch_cec_mutex, NULL, MUTEX_DRIVER,
1422 hal->halinfo.hw_interrupt);
1423 cv_init(&cec_new->in_callbacks_cv, NULL, CV_DRIVER,
1424 hal->halinfo.hw_interrupt);
1426 /* Initialize the Isoch CEC's member list */
1427 cec_new->cec_member_list_head = NULL;
1428 cec_new->cec_member_list_tail = NULL;
1430 /* Initialize the filters */
1431 cec_new->filter_min_speed = sii->si_speed;
1432 cec_new->filter_max_speed = sii->si_speed;
1433 cec_new->filter_current_speed = cec_new->filter_max_speed;
1434 cec_new->filter_channel_mask = sii->si_channel_mask;
1435 cec_new->bandwidth = sii->si_bandwidth;
1436 cec_new->state_transitions = ISOCH_CEC_FREE | ISOCH_CEC_JOIN |
1437 ISOCH_CEC_SETUP;
1439 mutex_enter(&hal->isoch_cec_list_mutex);
1441 /* Insert Isoch CEC into the HAL's list */
1442 s1394_isoch_cec_list_insert(hal, cec_new);
1444 mutex_exit(&hal->isoch_cec_list_mutex);
1447 * Join the newly created Isoch CEC
1449 jii.req_channel_mask = sii->si_channel_mask;
1450 jii.req_max_speed = sii->si_speed;
1451 jii.jii_options = T1394_TALKER;
1452 jii.isoch_cec_evts_arg = sii->single_evt_arg;
1454 /* All events are NULL except rsrc_fail_target() */
1455 jii.isoch_cec_evts.setup_target = NULL;
1456 jii.isoch_cec_evts.start_target = NULL;
1457 jii.isoch_cec_evts.stop_target = NULL;
1458 jii.isoch_cec_evts.stop_target = NULL;
1459 jii.isoch_cec_evts.teardown_target = NULL;
1460 jii.isoch_cec_evts.rsrc_fail_target = sii->rsrc_fail_target;
1462 ret = t1394_join_isoch_cec(t1394_hdl,
1463 (t1394_isoch_cec_handle_t)cec_new, 0, &jii);
1465 if (ret != DDI_SUCCESS) {
1466 ret = t1394_free_isoch_cec(t1394_hdl, flags,
1467 (t1394_isoch_cec_handle_t *)&cec_new);
1468 if (ret != DDI_SUCCESS) {
1469 /* Unable to free the Isoch CEC */
1470 ASSERT(0);
1473 /* Handle is nulled out before returning */
1474 *t1394_single_hdl = NULL;
1476 return (DDI_FAILURE);
1480 * Setup the isoch resources, etc.
1482 ret = t1394_setup_isoch_cec(t1394_hdl,
1483 (t1394_isoch_cec_handle_t)cec_new, 0, &err);
1485 if (ret != DDI_SUCCESS) {
1486 *result = err;
1488 /* Leave the Isoch CEC */
1489 ret = t1394_leave_isoch_cec(t1394_hdl,
1490 (t1394_isoch_cec_handle_t)cec_new, 0);
1491 if (ret != DDI_SUCCESS) {
1492 /* Unable to leave the Isoch CEC */
1493 ASSERT(0);
1496 /* Free up the Isoch CEC */
1497 ret = t1394_free_isoch_cec(t1394_hdl, flags,
1498 (t1394_isoch_cec_handle_t *)&cec_new);
1499 if (ret != DDI_SUCCESS) {
1500 /* Unable to free the Isoch CEC */
1501 ASSERT(0);
1504 /* Handle is nulled out before returning */
1505 *t1394_single_hdl = NULL;
1507 return (DDI_FAILURE);
1510 /* Return the setup_args - channel num and speed */
1511 mutex_enter(&cec_new->isoch_cec_mutex);
1512 output_args->channel_num = cec_new->realloc_chnl_num;
1513 mutex_exit(&cec_new->isoch_cec_mutex);
1515 /* Update the handle */
1516 *t1394_single_hdl = (t1394_isoch_single_handle_t)cec_new;
1518 return (DDI_SUCCESS);
1522 * Function: t1394_free_isoch_single()
1523 * Input(s): t1394_hdl The target "handle" returned by
1524 * t1394_attach()
1525 * t1394_single_hdl The isoch "handle" return by
1526 * t1394_alloc_isoch_single()
1527 * flags The flags parameter is unused (for now)
1529 * Output(s): None
1531 * Description: t1394_free_isoch_single() frees the isochronous resources
1532 * and the handle that were allocated during the call to
1533 * t1394_alloc_isoch_single().
1535 /* ARGSUSED */
1536 void
1537 t1394_free_isoch_single(t1394_handle_t t1394_hdl,
1538 t1394_isoch_single_handle_t *t1394_single_hdl, uint_t flags)
1540 s1394_isoch_cec_t *cec_curr;
1541 int ret;
1543 ASSERT(t1394_hdl != NULL);
1544 ASSERT(t1394_single_hdl != NULL);
1546 /* Convert the handle to an Isoch CEC pointer */
1547 cec_curr = (s1394_isoch_cec_t *)(*t1394_single_hdl);
1550 * Teardown the isoch resources, etc.
1552 ret = t1394_teardown_isoch_cec(t1394_hdl,
1553 (t1394_isoch_cec_handle_t)cec_curr, 0);
1554 if (ret != DDI_SUCCESS) {
1555 /* Unable to teardown the Isoch CEC */
1556 ASSERT(0);
1560 * Leave the Isoch CEC
1562 ret = t1394_leave_isoch_cec(t1394_hdl,
1563 (t1394_isoch_cec_handle_t)cec_curr, 0);
1564 if (ret != DDI_SUCCESS) {
1565 /* Unable to leave the Isoch CEC */
1566 ASSERT(0);
1570 * Free the Isoch CEC
1572 ret = t1394_free_isoch_cec(t1394_hdl, flags,
1573 (t1394_isoch_cec_handle_t *)&cec_curr);
1574 if (ret != DDI_SUCCESS) {
1575 /* Unable to free the Isoch CEC */
1576 ASSERT(0);
1579 /* Handle is nulled out before returning */
1580 *t1394_single_hdl = NULL;
1584 * Function: t1394_alloc_isoch_cec()
1585 * Input(s): t1394_hdl The target "handle" returned by
1586 * t1394_attach()
1587 * props The structure used to set up the
1588 * overall characteristics of for
1589 * the Isoch CEC.
1590 * flags The flags parameter is unused (for now)
1592 * Output(s): t1394_isoch_cec_hdl The Isoch CEC "handle" used in all
1593 * subsequent isoch_cec() calls
1595 * Description: t1394_alloc_isoch_cec() allocates and initializes an
1596 * isochronous channel event coordinator (Isoch CEC) for use
1597 * in managing and coordinating activity for an isoch channel
1599 /* ARGSUSED */
1601 t1394_alloc_isoch_cec(t1394_handle_t t1394_hdl, t1394_isoch_cec_props_t *props,
1602 uint_t flags, t1394_isoch_cec_handle_t *t1394_isoch_cec_hdl)
1604 s1394_hal_t *hal;
1605 s1394_isoch_cec_t *cec_new;
1606 uint64_t temp;
1608 ASSERT(t1394_hdl != NULL);
1609 ASSERT(t1394_isoch_cec_hdl != NULL);
1610 ASSERT(props != NULL);
1612 hal = ((s1394_target_t *)t1394_hdl)->on_hal;
1614 /* Check for invalid channel_mask */
1615 if (props->cec_channel_mask == 0) {
1616 return (DDI_FAILURE);
1619 /* Test conditions specific to T1394_NO_IRM_ALLOC */
1620 temp = props->cec_channel_mask;
1621 if (props->cec_options & T1394_NO_IRM_ALLOC) {
1622 /* If T1394_NO_IRM_ALLOC, then only one bit should be set */
1623 if (!ISP2(temp)) {
1624 return (DDI_FAILURE);
1627 /* If T1394_NO_IRM_ALLOC, then speeds should be equal */
1628 if (props->cec_min_speed != props->cec_max_speed) {
1629 return (DDI_FAILURE);
1633 /* Check for invalid bandwidth */
1634 if ((props->cec_bandwidth <= IEEE1394_BANDWIDTH_MIN) ||
1635 (props->cec_bandwidth > IEEE1394_BANDWIDTH_MAX)) {
1636 return (DDI_FAILURE);
1639 /* Allocate the Isoch CEC structure */
1640 cec_new = kmem_zalloc(sizeof (s1394_isoch_cec_t), KM_SLEEP);
1642 /* Initialize the structure type */
1643 cec_new->cec_type = S1394_PEER_TO_PEER;
1645 /* Create the mutex and "in_callbacks" cv */
1646 mutex_init(&cec_new->isoch_cec_mutex, NULL, MUTEX_DRIVER,
1647 hal->halinfo.hw_interrupt);
1648 cv_init(&cec_new->in_callbacks_cv, NULL, CV_DRIVER,
1649 hal->halinfo.hw_interrupt);
1651 /* Initialize the Isoch CEC's member list */
1652 cec_new->cec_member_list_head = NULL;
1653 cec_new->cec_member_list_tail = NULL;
1655 /* Initialize the filters */
1656 cec_new->filter_min_speed = props->cec_min_speed;
1657 cec_new->filter_max_speed = props->cec_max_speed;
1658 cec_new->filter_current_speed = cec_new->filter_max_speed;
1659 cec_new->filter_channel_mask = props->cec_channel_mask;
1660 cec_new->bandwidth = props->cec_bandwidth;
1661 cec_new->cec_options = props->cec_options;
1662 cec_new->state_transitions = ISOCH_CEC_FREE | ISOCH_CEC_JOIN |
1663 ISOCH_CEC_SETUP;
1665 mutex_enter(&hal->isoch_cec_list_mutex);
1667 /* Insert Isoch CEC into the HAL's list */
1668 s1394_isoch_cec_list_insert(hal, cec_new);
1670 mutex_exit(&hal->isoch_cec_list_mutex);
1672 /* Update the handle and return */
1673 *t1394_isoch_cec_hdl = (t1394_isoch_cec_handle_t)cec_new;
1675 return (DDI_SUCCESS);
1679 * Function: t1394_free_isoch_cec()
1680 * Input(s): t1394_hdl The target "handle" returned by
1681 * t1394_attach()
1682 * flags The flags parameter is unused (for now)
1683 * t1394_isoch_cec_hdl The Isoch CEC "handle" returned by
1684 * t1394_alloc_isoch_cec()
1686 * Output(s): DDI_SUCCESS Target successfully freed the Isoch CEC
1687 * DDI_FAILURE Target failed to free the Isoch CEC
1689 * Description: t1394_free_isoch_cec() attempts to free the Isoch CEC
1690 * structure. It will fail (DDI_FAILURE) if there are any
1691 * remaining members who have not yet left.
1693 /* ARGSUSED */
1695 t1394_free_isoch_cec(t1394_handle_t t1394_hdl, uint_t flags,
1696 t1394_isoch_cec_handle_t *t1394_isoch_cec_hdl)
1698 s1394_hal_t *hal;
1699 s1394_isoch_cec_t *cec_curr;
1701 ASSERT(t1394_hdl != NULL);
1702 ASSERT(t1394_isoch_cec_hdl != NULL);
1704 hal = ((s1394_target_t *)t1394_hdl)->on_hal;
1706 /* Convert the handle to an Isoch CEC pointer */
1707 cec_curr = (s1394_isoch_cec_t *)(*t1394_isoch_cec_hdl);
1709 /* Lock the Isoch CEC member list */
1710 mutex_enter(&cec_curr->isoch_cec_mutex);
1712 /* Are we in any callbacks? */
1713 if (CEC_IN_ANY_CALLBACKS(cec_curr)) {
1714 /* Unlock the Isoch CEC member list */
1715 mutex_exit(&cec_curr->isoch_cec_mutex);
1716 return (DDI_FAILURE);
1719 /* Is "free" a legal state transition? */
1720 if (CEC_TRANSITION_LEGAL(cec_curr, ISOCH_CEC_FREE) == 0) {
1721 /* Unlock the Isoch CEC member list */
1722 mutex_exit(&cec_curr->isoch_cec_mutex);
1723 return (DDI_FAILURE);
1725 mutex_exit(&cec_curr->isoch_cec_mutex);
1727 mutex_enter(&hal->isoch_cec_list_mutex);
1729 /* Remove Isoch CEC from HAL's list */
1730 s1394_isoch_cec_list_remove(hal, cec_curr);
1732 mutex_exit(&hal->isoch_cec_list_mutex);
1734 /* Destroy the Isoch CEC's mutex and cv */
1735 cv_destroy(&cec_curr->in_callbacks_cv);
1736 mutex_destroy(&cec_curr->isoch_cec_mutex);
1738 /* Free up the memory for the Isoch CEC struct */
1739 kmem_free(cec_curr, sizeof (s1394_isoch_cec_t));
1741 /* Update the handle and return */
1742 *t1394_isoch_cec_hdl = NULL;
1744 return (DDI_SUCCESS);
1748 * Function: t1394_join_isoch_cec()
1749 * Input(s): t1394_hdl The target "handle" returned by
1750 * t1394_attach()
1751 * t1394_isoch_cec_hdl The Isoch CEC "handle" returned by
1752 * t1394_alloc_isoch_cec()
1753 * flags The flags parameter is unused (for now)
1754 * join_isoch_info This structure provides infomation
1755 * about a target that wishes to join
1756 * the given Isoch CEC. It gives
1757 * max_speed, channel_mask, etc.
1759 * Output(s): DDI_SUCCESS Target successfully joined the
1760 * Isoch CEC
1761 * DDI_FAILURE Target failed to join the Isoch CEC
1763 * Description: t1394_join_isoch_cec() determines, based on the information
1764 * given in the join_isoch_info structure, if the target may
1765 * join the Isoch CEC. If it is determined that the target may
1766 * join, the specified callback routines are stored away for
1767 * later use in the coordination tasks.
1769 /* ARGSUSED */
1771 t1394_join_isoch_cec(t1394_handle_t t1394_hdl,
1772 t1394_isoch_cec_handle_t t1394_isoch_cec_hdl, uint_t flags,
1773 t1394_join_isochinfo_t *join_isoch_info)
1775 s1394_hal_t *hal;
1776 s1394_isoch_cec_t *cec_curr;
1777 s1394_isoch_cec_member_t *member_new;
1778 uint64_t check_mask;
1779 uint_t curr_max_speed;
1781 ASSERT(t1394_hdl != NULL);
1782 ASSERT(t1394_isoch_cec_hdl != NULL);
1784 hal = ((s1394_target_t *)t1394_hdl)->on_hal;
1786 /* Convert the handle to an Isoch CEC pointer */
1787 cec_curr = (s1394_isoch_cec_t *)t1394_isoch_cec_hdl;
1789 /* Allocate a new Isoch CEC member structure */
1790 member_new = kmem_zalloc(sizeof (s1394_isoch_cec_member_t), KM_SLEEP);
1792 /* Lock the Isoch CEC member list */
1793 mutex_enter(&cec_curr->isoch_cec_mutex);
1795 /* Are we in any callbacks? (Wait for them to finish) */
1796 while (CEC_IN_ANY_CALLBACKS(cec_curr)) {
1797 cec_curr->cec_want_wakeup = B_TRUE;
1798 cv_wait(&cec_curr->in_callbacks_cv,
1799 &cec_curr->isoch_cec_mutex);
1802 /* Is "join" a legal state transition? */
1803 if (CEC_TRANSITION_LEGAL(cec_curr, ISOCH_CEC_JOIN) == 0) {
1804 kmem_free(member_new, sizeof (s1394_isoch_cec_member_t));
1805 /* Unlock the Isoch CEC member list */
1806 mutex_exit(&cec_curr->isoch_cec_mutex);
1807 return (DDI_FAILURE);
1810 /* Check the channel mask for consistency */
1811 check_mask = join_isoch_info->req_channel_mask &
1812 cec_curr->filter_channel_mask;
1813 if (check_mask == 0) {
1814 kmem_free(member_new, sizeof (s1394_isoch_cec_member_t));
1815 /* Unlock the Isoch CEC member list */
1816 mutex_exit(&cec_curr->isoch_cec_mutex);
1817 return (DDI_FAILURE);
1820 /* Check for consistent speeds */
1821 if (join_isoch_info->req_max_speed < cec_curr->filter_min_speed) {
1822 kmem_free(member_new, sizeof (s1394_isoch_cec_member_t));
1823 /* Unlock the Isoch CEC member list */
1824 mutex_exit(&cec_curr->isoch_cec_mutex);
1825 return (DDI_FAILURE);
1826 } else if (join_isoch_info->req_max_speed <
1827 cec_curr->filter_current_speed) {
1828 curr_max_speed = join_isoch_info->req_max_speed;
1829 } else {
1830 curr_max_speed = cec_curr->filter_current_speed;
1833 /* Check for no more than one talker */
1834 if ((join_isoch_info->jii_options & T1394_TALKER) &&
1835 (cec_curr->cec_member_talker != NULL)) {
1836 kmem_free(member_new, sizeof (s1394_isoch_cec_member_t));
1837 /* Unlock the Isoch CEC member list */
1838 mutex_exit(&cec_curr->isoch_cec_mutex);
1839 return (DDI_FAILURE);
1842 /* Verify that all callbacks are non-NULL (for PEER_TO_PEER) */
1843 if ((cec_curr->cec_type == S1394_PEER_TO_PEER) &&
1844 ((join_isoch_info->isoch_cec_evts.setup_target == NULL) ||
1845 (join_isoch_info->isoch_cec_evts.start_target == NULL) ||
1846 (join_isoch_info->isoch_cec_evts.stop_target == NULL) ||
1847 (join_isoch_info->isoch_cec_evts.rsrc_fail_target == NULL) ||
1848 (join_isoch_info->isoch_cec_evts.teardown_target == NULL))) {
1849 /* Unlock the Isoch CEC member list */
1850 mutex_exit(&cec_curr->isoch_cec_mutex);
1851 return (DDI_FAILURE);
1854 /* Copy the events information into the struct */
1855 member_new->isoch_cec_evts = join_isoch_info->isoch_cec_evts;
1856 member_new->isoch_cec_evts_arg = join_isoch_info->isoch_cec_evts_arg;
1857 member_new->cec_mem_options = join_isoch_info->jii_options;
1858 member_new->cec_mem_target = (s1394_target_t *)t1394_hdl;
1860 /* Insert new member into Isoch CEC's member list */
1861 s1394_isoch_cec_member_list_insert(hal, cec_curr, member_new);
1863 /* Update the channel mask filter */
1864 cec_curr->filter_channel_mask = check_mask;
1866 /* Update the speed filter */
1867 cec_curr->filter_current_speed = curr_max_speed;
1869 /* Update the talker pointer (if necessary) */
1870 if (join_isoch_info->jii_options & T1394_TALKER)
1871 cec_curr->cec_member_talker = cec_curr->cec_member_list_head;
1874 * Now "leave" is a legal state transition
1875 * and "free" is an illegal state transition
1877 CEC_SET_LEGAL(cec_curr, ISOCH_CEC_LEAVE);
1878 CEC_SET_ILLEGAL(cec_curr, ISOCH_CEC_FREE);
1880 /* Unlock the Isoch CEC member list */
1881 mutex_exit(&cec_curr->isoch_cec_mutex);
1883 return (DDI_SUCCESS);
1887 * Function: t1394_leave_isoch_cec()
1888 * Input(s): t1394_hdl The target "handle" returned by
1889 * t1394_attach()
1890 * t1394_isoch_cec_hdl The Isoch CEC "handle" returned by
1891 * t1394_alloc_isoch_cec()
1892 * flags The flags parameter is unused (for now)
1894 * Output(s): DDI_SUCCESS Target successfully left the
1895 * Isoch CEC
1896 * DDI_FAILURE Target failed to leave the Isoch CEC
1898 * Description: t1394_leave_isoch_cec() is used by a target driver to remove
1899 * itself from the Isoch CEC's member list. It is possible
1900 * for this call to fail because the target is not found in
1901 * the current member list, or because it is not an appropriate
1902 * time for a target to leave.
1904 /* ARGSUSED */
1906 t1394_leave_isoch_cec(t1394_handle_t t1394_hdl,
1907 t1394_isoch_cec_handle_t t1394_isoch_cec_hdl, uint_t flags)
1909 s1394_hal_t *hal;
1910 s1394_isoch_cec_t *cec_curr;
1911 s1394_isoch_cec_member_t *member_curr;
1912 s1394_isoch_cec_member_t *member_temp;
1913 boolean_t found;
1914 uint64_t temp_channel_mask;
1915 uint_t temp_max_speed;
1917 ASSERT(t1394_hdl != NULL);
1918 ASSERT(t1394_isoch_cec_hdl != NULL);
1920 hal = ((s1394_target_t *)t1394_hdl)->on_hal;
1922 /* Convert the handle to an Isoch CEC pointer */
1923 cec_curr = (s1394_isoch_cec_t *)t1394_isoch_cec_hdl;
1925 /* Lock the Isoch CEC member list */
1926 mutex_enter(&cec_curr->isoch_cec_mutex);
1928 /* Are we in any callbacks? (Wait for them to finish) */
1929 while (CEC_IN_ANY_CALLBACKS(cec_curr)) {
1930 cec_curr->cec_want_wakeup = B_TRUE;
1931 cv_wait(&cec_curr->in_callbacks_cv,
1932 &cec_curr->isoch_cec_mutex);
1935 /* Is "leave" a legal state transition? */
1936 if (CEC_TRANSITION_LEGAL(cec_curr, ISOCH_CEC_LEAVE) == 0) {
1937 /* Unlock the Isoch CEC member list */
1938 mutex_exit(&cec_curr->isoch_cec_mutex);
1939 return (DDI_FAILURE);
1942 /* Find the Target on the CEC's member list */
1943 found = B_FALSE;
1944 temp_channel_mask = cec_curr->cec_alloc_props.cec_channel_mask;
1945 temp_max_speed = cec_curr->cec_alloc_props.cec_max_speed;
1946 member_curr = cec_curr->cec_member_list_head;
1947 while (member_curr != NULL) {
1948 if (member_curr->cec_mem_target ==
1949 (s1394_target_t *)t1394_hdl) {
1950 member_temp = member_curr;
1951 found = B_TRUE;
1952 } else {
1953 /* Keep track of channel mask and max speed info */
1954 temp_channel_mask &= member_curr->req_channel_mask;
1955 if (member_curr->req_max_speed < temp_max_speed)
1956 temp_max_speed = member_curr->req_max_speed;
1958 member_curr = member_curr->cec_mem_next;
1961 /* Target not found on this Isoch CEC */
1962 if (found == B_FALSE) {
1963 /* Unlock the Isoch CEC member list */
1964 mutex_exit(&cec_curr->isoch_cec_mutex);
1965 return (DDI_FAILURE);
1966 } else {
1967 /* This member's departure may change filter constraints */
1968 cec_curr->filter_current_speed = temp_max_speed;
1969 cec_curr->filter_channel_mask = temp_channel_mask;
1972 /* Remove member from Isoch CEC's member list */
1973 s1394_isoch_cec_member_list_remove(hal, cec_curr, member_temp);
1975 /* If we are removing the talker, then update the pointer */
1976 if (cec_curr->cec_member_talker == member_temp)
1977 cec_curr->cec_member_talker = NULL;
1979 /* Is the Isoch CEC's member list empty? */
1980 if ((cec_curr->cec_member_list_head == NULL) &&
1981 (cec_curr->cec_member_list_tail == NULL)) {
1983 * Now "free" _might_ be a legal state transition
1984 * if we aren't in setup or start phases and "leave"
1985 * is definitely an illegal state transition
1987 if (CEC_TRANSITION_LEGAL(cec_curr, ISOCH_CEC_JOIN) != 0)
1988 CEC_SET_LEGAL(cec_curr, ISOCH_CEC_FREE);
1989 CEC_SET_ILLEGAL(cec_curr, ISOCH_CEC_LEAVE);
1992 /* Unlock the Isoch CEC member list */
1993 mutex_exit(&cec_curr->isoch_cec_mutex);
1995 /* Free the Isoch CEC member structure */
1996 kmem_free(member_temp, sizeof (s1394_isoch_cec_member_t));
1998 return (DDI_SUCCESS);
2002 * Function: t1394_setup_isoch_cec()
2003 * Input(s): t1394_hdl The target "handle" returned by
2004 * t1394_attach()
2005 * t1394_isoch_cec_hdl The Isoch CEC "handle" returned by
2006 * t1394_alloc_isoch_cec()
2007 * flags The flags parameter is unused (for now)
2009 * Output(s): result Used to pass more specific info back
2010 * to target
2012 * Description: t1394_setup_isoch_cec() directs the 1394 Software Framework
2013 * to allocate isochronous resources and invoke the setup_target()
2014 * callback for each member of the Isoch CEC. This call may
2015 * fail because bandwidth was unavailable (T1394_ENO_BANDWIDTH),
2016 * channels were unavailable (T1394_ENO_CHANNEL), or one of the
2017 * member targets returned failure from its setup_target()
2018 * callback.
2020 /* ARGSUSED */
2022 t1394_setup_isoch_cec(t1394_handle_t t1394_hdl,
2023 t1394_isoch_cec_handle_t t1394_isoch_cec_hdl, uint_t flags, int *result)
2025 s1394_hal_t *hal;
2026 s1394_isoch_cec_t *cec_curr;
2027 s1394_isoch_cec_member_t *member_curr;
2028 t1394_setup_target_args_t target_args;
2029 uint64_t temp_chnl_mask;
2030 uint32_t old_chnl;
2031 uint32_t try_chnl;
2032 uint_t bw_alloc_units;
2033 uint_t generation;
2034 int chnl_num;
2035 int err;
2036 int ret;
2037 int j;
2038 int (*setup_callback)(t1394_isoch_cec_handle_t, opaque_t,
2039 t1394_setup_target_args_t *);
2041 ASSERT(t1394_hdl != NULL);
2042 ASSERT(t1394_isoch_cec_hdl != NULL);
2044 hal = ((s1394_target_t *)t1394_hdl)->on_hal;
2046 /* Convert the handle to an Isoch CEC pointer */
2047 cec_curr = (s1394_isoch_cec_t *)t1394_isoch_cec_hdl;
2049 /* Lock the Isoch CEC member list */
2050 mutex_enter(&cec_curr->isoch_cec_mutex);
2052 /* Are we in any callbacks? */
2053 if (CEC_IN_ANY_CALLBACKS(cec_curr)) {
2054 /* Unlock the Isoch CEC member list */
2055 mutex_exit(&cec_curr->isoch_cec_mutex);
2056 return (DDI_FAILURE);
2059 /* Is "setup" a legal state transition? */
2060 if (CEC_TRANSITION_LEGAL(cec_curr, ISOCH_CEC_SETUP) == 0) {
2061 /* Unlock the Isoch CEC member list */
2062 mutex_exit(&cec_curr->isoch_cec_mutex);
2063 return (DDI_FAILURE);
2066 /* If T1394_NO_IRM_ALLOC is set then don't allocate... do callbacks */
2067 if (cec_curr->cec_options & T1394_NO_IRM_ALLOC) {
2068 goto setup_do_callbacks;
2071 /* Allocate bandwidth and channels */
2072 for (j = 0; j < S1394_ISOCH_ALLOC_RETRIES; j++) {
2074 * Get the current generation number - don't
2075 * need the lock because we are read only here
2077 generation = hal->generation_count;
2079 /* Compute how much bandwidth is needed */
2080 bw_alloc_units = s1394_compute_bw_alloc_units(hal,
2081 cec_curr->bandwidth, cec_curr->filter_current_speed);
2083 /* Check that the generation has not changed - */
2084 /* don't need the lock (read only) */
2085 if (generation != hal->generation_count)
2086 continue;
2088 /* Unlock the Isoch CEC member list */
2089 mutex_exit(&cec_curr->isoch_cec_mutex);
2091 /* Try to allocate the bandwidth */
2092 ret = s1394_bandwidth_alloc(hal, bw_alloc_units, generation,
2093 &err);
2095 /* Lock the Isoch CEC member list */
2096 mutex_enter(&cec_curr->isoch_cec_mutex);
2098 /* If there was a bus reset, start over */
2099 if (ret == DDI_FAILURE) {
2100 if (err == CMD1394_EBUSRESET) {
2101 continue; /* start over and try again */
2102 } else {
2103 *result = T1394_ENO_BANDWIDTH;
2104 /* Unlock the Isoch CEC member list */
2105 mutex_exit(&cec_curr->isoch_cec_mutex);
2106 return (DDI_FAILURE);
2110 /* Check that the generation has not changed - */
2111 /* don't need the lock (read only) */
2112 if (generation != hal->generation_count)
2113 continue;
2116 * Allocate a channel
2117 * From IEEE 1394-1995, Section 8.3.2.3.8: "Bits
2118 * allocated in the CHANNELS_AVAILABLE_HI field of
2119 * this register shall start at bit zero (channel
2120 * number zero), and additional channel numbers shall
2121 * be represented in a monotonically increasing sequence
2122 * of bit numbers up to a maximum of bit 31 (channel
2123 * number 31). Bits allocated in the CHANNELS_AVAILABLE_LO
2124 * field of this register shall start at bit zero
2125 * (channel number 32), and additional channel numbers
2126 * shall be represented in a monotonically increasing
2127 * sequence of bit numbers up to a maximum of bit 31
2128 * (channel number 63).
2130 temp_chnl_mask = cec_curr->filter_channel_mask;
2131 for (chnl_num = 63; chnl_num >= 0; chnl_num--) {
2132 if ((temp_chnl_mask & 1) == 1) {
2133 try_chnl = (1 << ((63 - chnl_num) % 32));
2135 /* Unlock the Isoch CEC member list */
2136 mutex_exit(&cec_curr->isoch_cec_mutex);
2137 if (chnl_num < 32) {
2138 ret = s1394_channel_alloc(hal,
2139 try_chnl, generation,
2140 S1394_CHANNEL_ALLOC_HI, &old_chnl,
2141 &err);
2142 } else {
2143 ret = s1394_channel_alloc(hal,
2144 try_chnl, generation,
2145 S1394_CHANNEL_ALLOC_LO, &old_chnl,
2146 &err);
2148 /* Lock the Isoch CEC member list */
2149 mutex_enter(&cec_curr->isoch_cec_mutex);
2151 /* Did we get a channel? (or a bus reset) */
2152 if ((ret == DDI_SUCCESS) ||
2153 (err == CMD1394_EBUSRESET))
2154 break;
2156 temp_chnl_mask = temp_chnl_mask >> 1;
2159 /* If we've tried all the possible channels, then fail */
2160 if (chnl_num == 0) {
2161 *result = T1394_ENO_CHANNEL;
2163 * If we successfully allocate bandwidth, and
2164 * then fail getting a channel, we need to
2165 * free up the bandwidth
2168 /* Check that the generation has not changed */
2169 /* lock not needed here (read only) */
2170 if (generation != hal->generation_count)
2171 continue;
2173 /* Unlock the Isoch CEC member list */
2174 mutex_exit(&cec_curr->isoch_cec_mutex);
2176 /* Try to free up the bandwidth */
2177 ret = s1394_bandwidth_free(hal, bw_alloc_units,
2178 generation, &err);
2180 /* Lock the Isoch CEC member list */
2181 mutex_enter(&cec_curr->isoch_cec_mutex);
2183 if (ret == DDI_FAILURE) {
2184 if (err == CMD1394_EBUSRESET) {
2185 continue;
2186 } else {
2190 /* Unlock the Isoch CEC member list */
2191 mutex_exit(&cec_curr->isoch_cec_mutex);
2192 return (DDI_FAILURE);
2195 /* If we got a channel, we're done (else start over) */
2196 if (ret == DDI_SUCCESS)
2197 break;
2198 else if (err == CMD1394_EBUSRESET)
2199 continue;
2202 /* Have we gotten too many bus resets? */
2203 if (j == S1394_ISOCH_ALLOC_RETRIES) {
2204 *result = T1394_ENO_BANDWIDTH;
2205 /* Unlock the Isoch CEC member list */
2206 mutex_exit(&cec_curr->isoch_cec_mutex);
2207 return (DDI_FAILURE);
2210 cec_curr->realloc_valid = B_TRUE;
2211 cec_curr->realloc_chnl_num = chnl_num;
2212 cec_curr->realloc_bandwidth = cec_curr->bandwidth;
2213 cec_curr->realloc_speed = cec_curr->filter_current_speed;
2215 setup_do_callbacks:
2216 /* Call all of the setup_target() callbacks */
2217 target_args.channel_num = chnl_num;
2218 target_args.channel_speed = cec_curr->filter_current_speed;
2220 /* Now we are going into the callbacks */
2221 cec_curr->in_callbacks = B_TRUE;
2223 /* Unlock the Isoch CEC member list */
2224 mutex_exit(&cec_curr->isoch_cec_mutex);
2226 member_curr = cec_curr->cec_member_list_head;
2227 *result = 0;
2228 while (member_curr != NULL) {
2229 if (member_curr->isoch_cec_evts.setup_target != NULL) {
2230 setup_callback =
2231 member_curr->isoch_cec_evts.setup_target;
2232 ret = setup_callback(t1394_isoch_cec_hdl,
2233 member_curr->isoch_cec_evts_arg, &target_args);
2234 if (ret != DDI_SUCCESS)
2235 *result = T1394_ETARGET;
2237 member_curr = member_curr->cec_mem_next;
2240 /* Lock the Isoch CEC member list */
2241 mutex_enter(&cec_curr->isoch_cec_mutex);
2243 /* We are finished with the callbacks */
2244 cec_curr->in_callbacks = B_FALSE;
2245 if (cec_curr->cec_want_wakeup == B_TRUE) {
2246 cec_curr->cec_want_wakeup = B_FALSE;
2247 cv_broadcast(&cec_curr->in_callbacks_cv);
2251 * Now "start" and "teardown" are legal state transitions
2252 * and "join", "free", and "setup" are illegal state transitions
2254 CEC_SET_LEGAL(cec_curr, (ISOCH_CEC_START | ISOCH_CEC_TEARDOWN));
2255 CEC_SET_ILLEGAL(cec_curr, (ISOCH_CEC_JOIN | ISOCH_CEC_FREE |
2256 ISOCH_CEC_SETUP));
2258 /* Unlock the Isoch CEC member list */
2259 mutex_exit(&cec_curr->isoch_cec_mutex);
2261 /* Return DDI_FAILURE if any targets failed setup */
2262 if (*result != 0) {
2263 return (DDI_FAILURE);
2266 return (DDI_SUCCESS);
2270 * Function: t1394_start_isoch_cec()
2271 * Input(s): t1394_hdl The target "handle" returned by
2272 * t1394_attach()
2273 * t1394_isoch_cec_hdl The Isoch CEC "handle" returned by
2274 * t1394_alloc_isoch_cec()
2275 * flags The flags parameter is unused (for now)
2277 * Output(s): DDI_SUCCESS All start_target() callbacks returned
2278 * successfully
2279 * DDI_FAILURE One or more start_target() callbacks
2280 * returned failure
2282 * Description: t1394_start_isoch_cec() directs the 1394 Software Framework
2283 * to invoke each of the start_target() callbacks, first for
2284 * each listener, then for the talker.
2286 /* ARGSUSED */
2288 t1394_start_isoch_cec(t1394_handle_t t1394_hdl,
2289 t1394_isoch_cec_handle_t t1394_isoch_cec_hdl, uint_t flags)
2291 s1394_isoch_cec_t *cec_curr;
2292 s1394_isoch_cec_member_t *member_curr;
2293 int ret;
2294 boolean_t err;
2295 int (*start_callback)(t1394_isoch_cec_handle_t, opaque_t);
2297 ASSERT(t1394_hdl != NULL);
2298 ASSERT(t1394_isoch_cec_hdl != NULL);
2300 /* Convert the handle to an Isoch CEC pointer */
2301 cec_curr = (s1394_isoch_cec_t *)t1394_isoch_cec_hdl;
2303 /* Lock the Isoch CEC member list */
2304 mutex_enter(&cec_curr->isoch_cec_mutex);
2306 /* Are we in any callbacks? */
2307 if (CEC_IN_ANY_CALLBACKS(cec_curr)) {
2308 /* Unlock the Isoch CEC member list */
2309 mutex_exit(&cec_curr->isoch_cec_mutex);
2310 return (DDI_FAILURE);
2313 /* Is "start" a legal state transition? */
2314 if (CEC_TRANSITION_LEGAL(cec_curr, ISOCH_CEC_START) == 0) {
2315 /* Unlock the Isoch CEC member list */
2316 mutex_exit(&cec_curr->isoch_cec_mutex);
2317 return (DDI_FAILURE);
2320 /* Now we are going into the callbacks */
2321 cec_curr->in_callbacks = B_TRUE;
2323 /* Unlock the Isoch CEC member list */
2324 mutex_exit(&cec_curr->isoch_cec_mutex);
2327 * Call all of the start_target() callbacks
2328 * Start at the tail (listeners first) and
2329 * go toward the head (talker last)
2331 member_curr = cec_curr->cec_member_list_tail;
2332 err = B_FALSE;
2333 while (member_curr != NULL) {
2334 if (member_curr->isoch_cec_evts.start_target != NULL) {
2335 start_callback =
2336 member_curr->isoch_cec_evts.start_target;
2337 ret = start_callback(t1394_isoch_cec_hdl,
2338 member_curr->isoch_cec_evts_arg);
2339 if (ret != DDI_SUCCESS)
2340 err = B_TRUE;
2342 member_curr = member_curr->cec_mem_prev;
2345 /* Lock the Isoch CEC member list */
2346 mutex_enter(&cec_curr->isoch_cec_mutex);
2348 /* We are finished with the callbacks */
2349 cec_curr->in_callbacks = B_FALSE;
2350 if (cec_curr->cec_want_wakeup == B_TRUE) {
2351 cec_curr->cec_want_wakeup = B_FALSE;
2352 cv_broadcast(&cec_curr->in_callbacks_cv);
2356 * Now "stop" is a legal state transitions
2357 * and "start" and "teardown" are illegal state transitions
2359 CEC_SET_LEGAL(cec_curr, ISOCH_CEC_STOP);
2360 CEC_SET_ILLEGAL(cec_curr, (ISOCH_CEC_START | ISOCH_CEC_TEARDOWN));
2362 /* Unlock the Isoch CEC member list */
2363 mutex_exit(&cec_curr->isoch_cec_mutex);
2365 /* Return DDI_FAILURE if any targets failed start */
2366 if (err == B_TRUE) {
2367 return (DDI_FAILURE);
2370 return (DDI_SUCCESS);
2374 * Function: t1394_stop_isoch_cec()
2375 * Input(s): t1394_hdl The target "handle" returned by
2376 * t1394_attach()
2377 * t1394_isoch_cec_hdl The Isoch CEC "handle" returned by
2378 * t1394_alloc_isoch_cec()
2379 * flags The flags parameter is unused (for now)
2381 * Output(s): DDI_SUCCESS Target successfully stopped the
2382 * Isoch CEC
2383 * DDI_FAILURE Target failed to stop the Isoch CEC
2385 * Description: t1394_stop_isoch_cec() directs the 1394 Software Framework
2386 * to invoke each of the stop_target() callbacks, first for
2387 * the talker, then for each listener.
2388 * (This call will fail if it is called at an
2389 * inappropriate time, i.e. before the t1394_start_isoch_cec()
2390 * call, etc.)
2392 /* ARGSUSED */
2394 t1394_stop_isoch_cec(t1394_handle_t t1394_hdl,
2395 t1394_isoch_cec_handle_t t1394_isoch_cec_hdl, uint_t flags)
2397 s1394_isoch_cec_t *cec_curr;
2398 s1394_isoch_cec_member_t *member_curr;
2399 void (*stop_callback)(t1394_isoch_cec_handle_t, opaque_t);
2401 ASSERT(t1394_hdl != NULL);
2402 ASSERT(t1394_isoch_cec_hdl != NULL);
2404 /* Convert the handle to an Isoch CEC pointer */
2405 cec_curr = (s1394_isoch_cec_t *)t1394_isoch_cec_hdl;
2407 /* Lock the Isoch CEC member list */
2408 mutex_enter(&cec_curr->isoch_cec_mutex);
2410 /* Are we in any callbacks? */
2411 if (CEC_IN_ANY_CALLBACKS(cec_curr)) {
2412 /* Unlock the Isoch CEC member list */
2413 mutex_exit(&cec_curr->isoch_cec_mutex);
2414 return (DDI_FAILURE);
2417 /* Is "stop" a legal state transition? */
2418 if (CEC_TRANSITION_LEGAL(cec_curr, ISOCH_CEC_STOP) == 0) {
2419 /* Unlock the Isoch CEC member list */
2420 mutex_exit(&cec_curr->isoch_cec_mutex);
2421 return (DDI_FAILURE);
2424 /* Now we are going into the callbacks */
2425 cec_curr->in_callbacks = B_TRUE;
2427 /* Unlock the Isoch CEC member list */
2428 mutex_exit(&cec_curr->isoch_cec_mutex);
2431 * Call all of the stop_target() callbacks
2432 * Start at the head (talker first) and
2433 * go toward the tail (listeners last)
2435 member_curr = cec_curr->cec_member_list_head;
2436 while (member_curr != NULL) {
2437 if (member_curr->isoch_cec_evts.stop_target != NULL) {
2438 stop_callback =
2439 member_curr->isoch_cec_evts.stop_target;
2440 stop_callback(t1394_isoch_cec_hdl,
2441 member_curr->isoch_cec_evts_arg);
2443 member_curr = member_curr->cec_mem_next;
2446 /* Lock the Isoch CEC member list */
2447 mutex_enter(&cec_curr->isoch_cec_mutex);
2449 /* We are finished with the callbacks */
2450 cec_curr->in_callbacks = B_FALSE;
2451 if (cec_curr->cec_want_wakeup == B_TRUE) {
2452 cec_curr->cec_want_wakeup = B_FALSE;
2453 cv_broadcast(&cec_curr->in_callbacks_cv);
2457 * Now "start" and "teardown" are legal state transitions
2458 * and "stop" is an illegal state transitions
2460 CEC_SET_LEGAL(cec_curr, (ISOCH_CEC_START | ISOCH_CEC_TEARDOWN));
2461 CEC_SET_ILLEGAL(cec_curr, ISOCH_CEC_STOP);
2463 /* Unlock the Isoch CEC member list */
2464 mutex_exit(&cec_curr->isoch_cec_mutex);
2466 return (DDI_SUCCESS);
2470 * Function: t1394_teardown_isoch_cec()
2471 * Input(s): t1394_hdl The target "handle" returned by
2472 * t1394_attach()
2473 * t1394_isoch_cec_hdl The Isoch CEC "handle" returned by
2474 * t1394_alloc_isoch_cec()
2475 * flags The flags parameter is unused (for now)
2477 * Output(s): DDI_SUCCESS Target successfully tore down the
2478 * Isoch CEC
2479 * DDI_FAILURE Target failed to tear down the
2480 * Isoch CEC
2482 * Description: t1394_teardown_isoch_cec() directs the 1394 Software Framework
2483 * to free up any isochronous resources we might be holding and
2484 * call all of the teardown_target() callbacks.
2485 * (This call will fail if it is called at an
2486 * inappropriate time, i.e. before the t1394_start_isoch_cec()
2487 * call, before the t1394_stop_isoch_cec, etc.
2489 /* ARGSUSED */
2491 t1394_teardown_isoch_cec(t1394_handle_t t1394_hdl,
2492 t1394_isoch_cec_handle_t t1394_isoch_cec_hdl, uint_t flags)
2494 s1394_hal_t *hal;
2495 s1394_isoch_cec_t *cec_curr;
2496 s1394_isoch_cec_member_t *member_curr;
2497 uint32_t chnl_mask;
2498 uint32_t old_chnl_mask;
2499 uint_t bw_alloc_units;
2500 uint_t generation;
2501 int ret;
2502 int err;
2503 void (*teardown_callback)(t1394_isoch_cec_handle_t, opaque_t);
2505 ASSERT(t1394_hdl != NULL);
2506 ASSERT(t1394_isoch_cec_hdl != NULL);
2508 hal = ((s1394_target_t *)t1394_hdl)->on_hal;
2510 /* Convert the handle to an Isoch CEC pointer */
2511 cec_curr = (s1394_isoch_cec_t *)t1394_isoch_cec_hdl;
2513 /* Lock the Isoch CEC member list */
2514 mutex_enter(&cec_curr->isoch_cec_mutex);
2516 /* Are we in any callbacks? */
2517 if (CEC_IN_ANY_CALLBACKS(cec_curr)) {
2518 /* Unlock the Isoch CEC member list */
2519 mutex_exit(&cec_curr->isoch_cec_mutex);
2520 return (DDI_FAILURE);
2523 /* Is "teardown" a legal state transition? */
2524 if (CEC_TRANSITION_LEGAL(cec_curr, ISOCH_CEC_TEARDOWN) == 0) {
2525 /* Unlock the Isoch CEC member list */
2526 mutex_exit(&cec_curr->isoch_cec_mutex);
2527 return (DDI_FAILURE);
2530 /* If T1394_NO_IRM_ALLOC is set then don't free... do callbacks */
2531 if (cec_curr->cec_options & T1394_NO_IRM_ALLOC) {
2532 goto teardown_do_callbacks;
2535 /* If nothing has been allocated or we failed to */
2536 /* reallocate, then we are done... call the callbacks */
2537 if ((cec_curr->realloc_valid == B_FALSE) ||
2538 (cec_curr->realloc_failed == B_TRUE)) {
2539 goto teardown_do_callbacks;
2543 * Get the current generation number - don't need the
2544 * topology tree mutex here because it is read-only, and
2545 * there is a race condition with or without it.
2547 generation = hal->generation_count;
2549 /* Compute the amount bandwidth to free */
2550 bw_alloc_units = s1394_compute_bw_alloc_units(hal,
2551 cec_curr->bandwidth, cec_curr->realloc_speed);
2553 /* Check that the generation has not changed - */
2554 /* don't need the lock (read only) */
2555 if (generation != hal->generation_count)
2556 goto teardown_do_callbacks;
2558 /* Unlock the Isoch CEC member list */
2559 mutex_exit(&cec_curr->isoch_cec_mutex);
2561 /* Try to free up the bandwidth */
2562 ret = s1394_bandwidth_free(hal, bw_alloc_units, generation, &err);
2564 /* Lock the Isoch CEC member list */
2565 mutex_enter(&cec_curr->isoch_cec_mutex);
2567 if (ret == DDI_FAILURE) {
2568 if (err == CMD1394_EBUSRESET) {
2569 goto teardown_do_callbacks;
2570 } else {
2574 /* Free the allocated channel */
2575 chnl_mask = (1 << ((63 - cec_curr->realloc_chnl_num) % 32));
2577 /* Unlock the Isoch CEC member list */
2578 mutex_exit(&cec_curr->isoch_cec_mutex);
2579 if (cec_curr->realloc_chnl_num < 32) {
2580 ret = s1394_channel_free(hal, chnl_mask, generation,
2581 S1394_CHANNEL_ALLOC_HI, &old_chnl_mask, &err);
2582 } else {
2583 ret = s1394_channel_free(hal, chnl_mask, generation,
2584 S1394_CHANNEL_ALLOC_LO, &old_chnl_mask, &err);
2586 /* Lock the Isoch CEC member list */
2587 mutex_enter(&cec_curr->isoch_cec_mutex);
2589 if (ret == DDI_FAILURE) {
2590 if (err == CMD1394_EBUSRESET) {
2591 goto teardown_do_callbacks;
2592 } else {
2596 teardown_do_callbacks:
2597 /* From here on reallocation is unnecessary */
2598 cec_curr->realloc_valid = B_FALSE;
2599 cec_curr->realloc_chnl_num = 0;
2600 cec_curr->realloc_bandwidth = 0;
2602 /* Now we are going into the callbacks */
2603 cec_curr->in_callbacks = B_TRUE;
2605 /* Unlock the Isoch CEC member list */
2606 mutex_exit(&cec_curr->isoch_cec_mutex);
2608 /* Call all of the teardown_target() callbacks */
2609 member_curr = cec_curr->cec_member_list_head;
2610 while (member_curr != NULL) {
2611 if (member_curr->isoch_cec_evts.teardown_target != NULL) {
2612 teardown_callback =
2613 member_curr->isoch_cec_evts.teardown_target;
2614 teardown_callback(t1394_isoch_cec_hdl,
2615 member_curr->isoch_cec_evts_arg);
2617 member_curr = member_curr->cec_mem_next;
2620 /* Lock the Isoch CEC member list */
2621 mutex_enter(&cec_curr->isoch_cec_mutex);
2623 /* We are finished with the callbacks */
2624 cec_curr->in_callbacks = B_FALSE;
2625 if (cec_curr->cec_want_wakeup == B_TRUE) {
2626 cec_curr->cec_want_wakeup = B_FALSE;
2627 cv_broadcast(&cec_curr->in_callbacks_cv);
2631 * Now "join" and "setup" are legal state transitions
2632 * and "start" and "teardown" are illegal state transitions
2634 CEC_SET_LEGAL(cec_curr, (ISOCH_CEC_JOIN | ISOCH_CEC_SETUP));
2635 CEC_SET_ILLEGAL(cec_curr, (ISOCH_CEC_START | ISOCH_CEC_TEARDOWN));
2637 /* And if the member list is empty, then "free" is legal too */
2638 if ((cec_curr->cec_member_list_head == NULL) &&
2639 (cec_curr->cec_member_list_tail == NULL)) {
2640 CEC_SET_LEGAL(cec_curr, ISOCH_CEC_FREE);
2643 /* Unlock the Isoch CEC member list */
2644 mutex_exit(&cec_curr->isoch_cec_mutex);
2645 return (DDI_SUCCESS);
2649 * Function: t1394_alloc_isoch_dma()
2650 * Input(s): t1394_hdl The target "handle" returned by
2651 * t1394_attach()
2652 * idi This structure contains information
2653 * for configuring the data flow for
2654 * isochronous DMA
2655 * flags The flags parameter is unused (for now)
2657 * Output(s): t1394_idma_hdl The IDMA "handle" used in all
2658 * subsequent isoch_dma() calls
2659 * result Used to pass more specific info back
2660 * to target
2662 * Description: t1394_alloc_isoch_dma() allocates and initializes an
2663 * isochronous DMA resource for transmitting or receiving
2664 * isochronous data. If it fails, result may hold
2665 * T1394_EIDMA_NO_RESRCS, indicating that no isoch DMA resource
2666 * are available.
2668 /* ARGSUSED */
2670 t1394_alloc_isoch_dma(t1394_handle_t t1394_hdl,
2671 id1394_isoch_dmainfo_t *idi, uint_t flags,
2672 t1394_isoch_dma_handle_t *t1394_idma_hdl, int *result)
2674 s1394_hal_t *hal;
2675 int ret;
2677 ASSERT(t1394_hdl != NULL);
2678 ASSERT(idi != NULL);
2679 ASSERT(t1394_idma_hdl != NULL);
2681 /* Find the HAL this target resides on */
2682 hal = ((s1394_target_t *)t1394_hdl)->on_hal;
2684 /* Sanity check dma options. If talk enabled, listen should be off */
2685 if ((idi->idma_options & ID1394_TALK) &&
2686 (idi->idma_options != ID1394_TALK)) {
2687 *result = T1394_EIDMA_CONFLICT;
2688 return (DDI_FAILURE);
2691 /* Only one listen mode allowed */
2692 if ((idi->idma_options & ID1394_LISTEN_PKT_MODE) &&
2693 (idi->idma_options & ID1394_LISTEN_BUF_MODE)) {
2694 *result = T1394_EIDMA_CONFLICT;
2695 return (DDI_FAILURE);
2698 /* Have HAL alloc a resource and compile ixl */
2699 ret = HAL_CALL(hal).alloc_isoch_dma(hal->halinfo.hal_private, idi,
2700 (void **)t1394_idma_hdl, result);
2702 if (ret != DDI_SUCCESS) {
2703 if (*result == IXL1394_ENO_DMA_RESRCS) {
2704 *result = T1394_EIDMA_NO_RESRCS;
2708 return (ret);
2712 * Function: t1394_free_isoch_dma()
2713 * Input(s): t1394_hdl The target "handle" returned by
2714 * t1394_attach()
2715 * flags The flags parameter is unused (for now)
2716 * t1394_idma_hdl The IDMA "handle" returned by
2717 * t1394_alloc_isoch_dma()
2719 * Output(s): None
2721 * Description: t1394_free_isoch_dma() is used to free all DMA resources
2722 * allocated for the isoch stream associated with t1394_idma_hdl.
2724 /* ARGSUSED */
2725 void
2726 t1394_free_isoch_dma(t1394_handle_t t1394_hdl, uint_t flags,
2727 t1394_isoch_dma_handle_t *t1394_idma_hdl)
2729 s1394_hal_t *hal;
2731 ASSERT(t1394_hdl != NULL);
2732 ASSERT(*t1394_idma_hdl != NULL);
2734 /* Find the HAL this target resides on */
2735 hal = ((s1394_target_t *)t1394_hdl)->on_hal;
2737 /* Tell HAL to release local isoch dma resources */
2738 HAL_CALL(hal).free_isoch_dma(hal->halinfo.hal_private, *t1394_idma_hdl);
2740 /* Null out isoch handle */
2741 *t1394_idma_hdl = NULL;
2745 * Function: t1394_start_isoch_dma()
2746 * Input(s): t1394_hdl The target "handle" returned by
2747 * t1394_attach()
2748 * t1394_idma_hdl The IDMA "handle" returned by
2749 * t1394_alloc_isoch_dma()
2750 * idma_ctrlinfo This structure contains control args
2751 * used when starting isoch DMA for
2752 * the allocated resource
2753 * flags One flag defined - ID1394_START_ON_CYCLE
2755 * Output(s): result Used to pass more specific info back
2756 * to target
2758 * Description: t1394_start_isoch_dma() is used to start DMA for the isoch
2759 * stream associated with t1394_idma_hdl.
2761 /* ARGSUSED */
2763 t1394_start_isoch_dma(t1394_handle_t t1394_hdl,
2764 t1394_isoch_dma_handle_t t1394_idma_hdl,
2765 id1394_isoch_dma_ctrlinfo_t *idma_ctrlinfo, uint_t flags,
2766 int *result)
2768 s1394_hal_t *hal;
2769 int ret;
2771 ASSERT(t1394_hdl != NULL);
2772 ASSERT(t1394_idma_hdl != NULL);
2773 ASSERT(idma_ctrlinfo != NULL);
2775 /* Find the HAL this target resides on */
2776 hal = ((s1394_target_t *)t1394_hdl)->on_hal;
2778 ret = HAL_CALL(hal).start_isoch_dma(hal->halinfo.hal_private,
2779 (void *)t1394_idma_hdl, idma_ctrlinfo, flags, result);
2781 return (ret);
2785 * Function: t1394_stop_isoch_dma()
2786 * Input(s): t1394_hdl The target "handle" returned by
2787 * t1394_attach()
2788 * t1394_idma_hdl The IDMA "handle" returned by
2789 * t1394_alloc_isoch_dma()
2790 * flags The flags parameter is unused (for now)
2792 * Output(s): None
2794 * Description: t1394_stop_isoch_dma() is used to stop DMA for the isoch
2795 * stream associated with t1394_idma_hdl.
2797 /* ARGSUSED */
2798 void
2799 t1394_stop_isoch_dma(t1394_handle_t t1394_hdl,
2800 t1394_isoch_dma_handle_t t1394_idma_hdl, uint_t flags)
2802 s1394_hal_t *hal;
2803 int result;
2805 ASSERT(t1394_hdl != NULL);
2806 ASSERT(t1394_idma_hdl != NULL);
2808 /* Find the HAL this target resides on */
2809 hal = ((s1394_target_t *)t1394_hdl)->on_hal;
2811 HAL_CALL(hal).stop_isoch_dma(hal->halinfo.hal_private,
2812 (void *)t1394_idma_hdl, &result);
2816 * Function: t1394_update_isoch_dma()
2817 * Input(s): t1394_hdl The target "handle" returned by
2818 * t1394_attach()
2819 * t1394_idma_hdl The IDMA "handle" returned by
2820 * t1394_alloc_isoch_dma()
2821 * idma_updateinfo This structure contains ixl command args
2822 * used when updating args in an
2823 * existing list of ixl commands with
2824 * args in a new list of ixl commands.
2825 * flags The flags parameter is unused (for now)
2827 * Output(s): result Used to pass more specific info back
2828 * to target
2830 * Description: t1394_update_isoch_dma() is used to alter an IXL program that
2831 * has already been built (compiled) by t1394_alloc_isoch_dma().
2833 /* ARGSUSED */
2835 t1394_update_isoch_dma(t1394_handle_t t1394_hdl,
2836 t1394_isoch_dma_handle_t t1394_idma_hdl,
2837 id1394_isoch_dma_updateinfo_t *idma_updateinfo, uint_t flags,
2838 int *result)
2840 s1394_hal_t *hal;
2841 int ret;
2843 ASSERT(t1394_hdl != NULL);
2844 ASSERT(t1394_idma_hdl != NULL);
2845 ASSERT(idma_updateinfo != NULL);
2847 /* Find the HAL this target resides on */
2848 hal = ((s1394_target_t *)t1394_hdl)->on_hal;
2850 ret = HAL_CALL(hal).update_isoch_dma(hal->halinfo.hal_private,
2851 (void *)t1394_idma_hdl, idma_updateinfo, flags, result);
2853 return (ret);
2857 * Function: t1394_initiate_bus_reset()
2858 * Input(s): t1394_hdl The target "handle" returned by
2859 * t1394_attach()
2860 * flags The flags parameter is unused (for now)
2862 * Output(s): None
2864 * Description: t1394_initiate_bus_reset() determines whether the local
2865 * device has a P1394A PHY and will support the arbitrated
2866 * short bus reset. If not, it will initiate a normal bus reset.
2868 /* ARGSUSED */
2869 void
2870 t1394_initiate_bus_reset(t1394_handle_t t1394_hdl, uint_t flags)
2872 s1394_hal_t *hal;
2873 int ret;
2875 ASSERT(t1394_hdl != NULL);
2877 /* Find the HAL this target resides on */
2878 hal = ((s1394_target_t *)t1394_hdl)->on_hal;
2880 /* Reset the bus */
2881 if (hal->halinfo.phy == H1394_PHY_1394A) {
2882 ret = HAL_CALL(hal).short_bus_reset(hal->halinfo.hal_private);
2883 if (ret != DDI_SUCCESS) {
2885 } else {
2886 ret = HAL_CALL(hal).bus_reset(hal->halinfo.hal_private);
2887 if (ret != DDI_SUCCESS) {
2893 * Function: t1394_get_topology_map()
2894 * Input(s): t1394_hdl The target "handle" returned by
2895 * t1394_attach()
2896 * bus_generation The current generation
2897 * tm_length The size of the tm_buffer given
2898 * flags The flags parameter is unused (for now)
2900 * Output(s): tm_buffer Filled in by the 1394 Software Framework
2901 * with the contents of the local
2902 * TOPOLOGY_MAP
2904 * Description: t1394_get_topology_map() returns the 1394 TOPLOGY_MAP. See
2905 * IEEE 1394-1995 Section 8.2.3.4.1 for format information. This
2906 * call can fail if there is a generation mismatch or the
2907 * tm_buffer is too small to hold the TOPOLOGY_MAP.
2909 /* ARGSUSED */
2911 t1394_get_topology_map(t1394_handle_t t1394_hdl, uint_t bus_generation,
2912 size_t tm_length, uint_t flags, uint32_t *tm_buffer)
2914 s1394_hal_t *hal;
2915 uint32_t *tm_ptr;
2916 uint_t length;
2918 ASSERT(t1394_hdl != NULL);
2920 /* Find the HAL this target resides on */
2921 hal = ((s1394_target_t *)t1394_hdl)->on_hal;
2923 /* Lock the topology tree */
2924 mutex_enter(&hal->topology_tree_mutex);
2926 /* Check the bus_generation for the Topology Map */
2927 if (bus_generation != hal->generation_count) {
2928 /* Unlock the topology tree */
2929 mutex_exit(&hal->topology_tree_mutex);
2930 return (DDI_FAILURE);
2933 tm_ptr = (uint32_t *)hal->CSR_topology_map;
2934 length = tm_ptr[0] >> 16;
2935 length = length * 4; /* Bytes instead of quadlets */
2936 length = length + 4; /* don't forget the first quad */
2938 /* Check that the buffer is big enough */
2939 if (length > (uint_t)tm_length) {
2940 /* Unlock the topology tree */
2941 mutex_exit(&hal->topology_tree_mutex);
2942 return (DDI_FAILURE);
2945 /* Do the copy */
2946 bcopy(tm_ptr, tm_buffer, length);
2948 /* Unlock the topology tree */
2949 mutex_exit(&hal->topology_tree_mutex);
2950 return (DDI_SUCCESS);
2954 * Function: t1394_CRC16()
2955 * Input(s): d The data to compute the CRC-16 for
2956 * crc_length The length into the data to compute for
2957 * flags The flags parameter is unused (for now)
2959 * Output(s): CRC The CRC-16 computed for the length
2960 * of data specified
2962 * Description: t1394_CRC16() implements ISO/IEC 13213:1994, ANSI/IEEE Std
2963 * 1212, 1994 - 8.1.5.
2965 /* ARGSUSED */
2966 uint_t
2967 t1394_CRC16(uint32_t *d, size_t crc_length, uint_t flags)
2969 /* Implements ISO/IEC 13213:1994, */
2970 /* ANSI/IEEE Std 1212, 1994 - 8.1.5 */
2971 uint_t ret;
2973 ret = s1394_CRC16((uint_t *)d, (uint_t)crc_length);
2975 return (ret);
2979 * Function: t1394_add_cfgrom_entry()
2980 * Input(s): t1394_hdl The target "handle" returned by
2981 * t1394_attach()
2982 * cfgrom_entryinfo This structure holds the cfgrom key,
2983 * buffer, and size
2984 * flags The flags parameter is unused (for now)
2986 * Output(s): t1394_cfgrom_hdl The ConfigROM "handle" used in
2987 * t1394_rem_cfgrom_entry()
2988 * result Used to pass more specific info back
2989 * to target
2991 * Description: t1394_add_cfgrom_entry() adds an entry to the local Config ROM,
2992 * updating the directory entries as necessary. This call could
2993 * fail because there is no room for the new entry in Config ROM
2994 * (T1394_ECFGROM_FULL), the key is invalid (T1394_EINVALID_PARAM),
2995 * or it was called in interrupt context (T1394_EINVALID_CONTEXT).
2997 /* ARGSUSED */
2999 t1394_add_cfgrom_entry(t1394_handle_t t1394_hdl,
3000 t1394_cfgrom_entryinfo_t *cfgrom_entryinfo, uint_t flags,
3001 t1394_cfgrom_handle_t *t1394_cfgrom_hdl, int *result)
3003 s1394_hal_t *hal;
3004 s1394_target_t *target;
3005 int ret;
3006 uint_t key;
3007 uint_t size;
3008 uint32_t *buffer;
3010 ASSERT(t1394_hdl != NULL);
3012 target = (s1394_target_t *)t1394_hdl;
3014 key = cfgrom_entryinfo->ce_key;
3015 buffer = cfgrom_entryinfo->ce_buffer;
3016 size = (uint_t)cfgrom_entryinfo->ce_size;
3018 /* Check for a valid size */
3019 if (size == 0) {
3020 *result = T1394_EINVALID_PARAM;
3021 return (DDI_FAILURE);
3024 /* Check for a valid key type */
3025 if (((key << IEEE1212_KEY_VALUE_SHIFT) & IEEE1212_KEY_TYPE_MASK) == 0) {
3026 *result = T1394_EINVALID_PARAM;
3027 return (DDI_FAILURE);
3030 /* Find the HAL this target resides on */
3031 hal = target->on_hal;
3033 /* Is this on the interrupt stack? */
3034 if (servicing_interrupt()) {
3035 *result = T1394_EINVALID_CONTEXT;
3036 return (DDI_FAILURE);
3039 /* Lock the Config ROM buffer */
3040 mutex_enter(&hal->local_config_rom_mutex);
3042 ret = s1394_add_config_rom_entry(hal, key, buffer, size,
3043 (void **)t1394_cfgrom_hdl, result);
3044 if (ret != DDI_SUCCESS) {
3045 if (*result == CMD1394_ERSRC_CONFLICT)
3046 *result = T1394_ECFGROM_FULL;
3047 mutex_exit(&hal->local_config_rom_mutex);
3049 return (ret);
3052 /* Setup the timeout function */
3053 if (hal->config_rom_timer_set == B_FALSE) {
3054 hal->config_rom_timer_set = B_TRUE;
3055 mutex_exit(&hal->local_config_rom_mutex);
3056 hal->config_rom_timer =
3057 timeout(s1394_update_config_rom_callback, hal,
3058 drv_usectohz(CONFIG_ROM_UPDATE_DELAY * 1000));
3059 } else {
3060 mutex_exit(&hal->local_config_rom_mutex);
3063 return (ret);
3067 * Function: t1394_rem_cfgrom_entry()
3068 * Input(s): t1394_hdl The target "handle" returned by
3069 * t1394_attach()
3070 * flags The flags parameter is unused (for now)
3071 * t1394_cfgrom_hdl The ConfigROM "handle" returned by
3072 * t1394_add_cfgrom_entry()
3074 * Output(s): result Used to pass more specific info back
3075 * to target
3077 * Description: t1394_rem_cfgrom_entry() is used to remove a previously added
3078 * Config ROM entry (indicated by t1394_cfgrom_hdl).
3080 /* ARGSUSED */
3082 t1394_rem_cfgrom_entry(t1394_handle_t t1394_hdl, uint_t flags,
3083 t1394_cfgrom_handle_t *t1394_cfgrom_hdl, int *result)
3085 s1394_hal_t *hal;
3086 s1394_target_t *target;
3087 int ret;
3089 ASSERT(t1394_hdl != NULL);
3091 target = (s1394_target_t *)t1394_hdl;
3093 /* Find the HAL this target resides on */
3094 hal = target->on_hal;
3096 /* Is this on the interrupt stack? */
3097 if (servicing_interrupt()) {
3098 *result = T1394_EINVALID_CONTEXT;
3099 return (DDI_FAILURE);
3102 /* Lock the Config ROM buffer */
3103 mutex_enter(&hal->local_config_rom_mutex);
3105 ret = s1394_remove_config_rom_entry(hal, (void **)t1394_cfgrom_hdl,
3106 result);
3107 if (ret != DDI_SUCCESS) {
3108 mutex_exit(&hal->local_config_rom_mutex);
3109 return (ret);
3112 /* Setup the timeout function */
3113 if (hal->config_rom_timer_set == B_FALSE) {
3114 hal->config_rom_timer_set = B_TRUE;
3115 mutex_exit(&hal->local_config_rom_mutex);
3116 hal->config_rom_timer =
3117 timeout(s1394_update_config_rom_callback, hal,
3118 drv_usectohz(CONFIG_ROM_UPDATE_DELAY * 1000));
3119 } else {
3120 mutex_exit(&hal->local_config_rom_mutex);
3123 return (ret);
3127 * Function: t1394_get_targetinfo()
3128 * Input(s): t1394_hdl The target "handle" returned by
3129 * t1394_attach()
3130 * bus_generation The current generation
3131 * flags The flags parameter is unused (for now)
3133 * Output(s): targetinfo Structure containing max_payload,
3134 * max_speed, and target node ID.
3136 * Description: t1394_get_targetinfo() is used to retrieve information specific
3137 * to a target device. It will fail if the generation given
3138 * does not match the current generation.
3140 /* ARGSUSED */
3142 t1394_get_targetinfo(t1394_handle_t t1394_hdl, uint_t bus_generation,
3143 uint_t flags, t1394_targetinfo_t *targetinfo)
3145 s1394_hal_t *hal;
3146 s1394_target_t *target;
3147 uint_t dev;
3148 uint_t curr;
3149 uint_t from_node;
3150 uint_t to_node;
3152 ASSERT(t1394_hdl != NULL);
3154 /* Find the HAL this target resides on */
3155 hal = ((s1394_target_t *)t1394_hdl)->on_hal;
3157 target = (s1394_target_t *)t1394_hdl;
3159 /* Lock the topology tree */
3160 mutex_enter(&hal->topology_tree_mutex);
3162 /* Check the bus_generation */
3163 if (bus_generation != hal->generation_count) {
3164 /* Unlock the topology tree */
3165 mutex_exit(&hal->topology_tree_mutex);
3166 return (DDI_FAILURE);
3169 rw_enter(&hal->target_list_rwlock, RW_READER);
3171 * If there is no node, report T1394_INVALID_NODEID for target_nodeID;
3172 * current_max_speed and current_max_payload are undefined for this
3173 * case.
3175 if (((target->target_state & S1394_TARG_GONE) != 0) ||
3176 (target->on_node == NULL)) {
3177 targetinfo->target_nodeID = T1394_INVALID_NODEID;
3178 } else {
3179 targetinfo->target_nodeID =
3180 (target->on_hal->node_id & IEEE1394_BUS_NUM_MASK) |
3181 target->on_node->node_num;
3183 from_node = (target->on_hal->node_id) & IEEE1394_NODE_NUM_MASK;
3184 to_node = target->on_node->node_num;
3186 targetinfo->current_max_speed = (uint_t)s1394_speed_map_get(
3187 hal, from_node, to_node);
3189 /* Get current_max_payload */
3190 s1394_get_maxpayload(target, &dev, &curr);
3191 targetinfo->current_max_payload = curr;
3194 rw_exit(&hal->target_list_rwlock);
3195 /* Unlock the topology tree */
3196 mutex_exit(&hal->topology_tree_mutex);
3197 return (DDI_SUCCESS);