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]
22 * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
28 * 1394 Target Driver Interface
29 * This file contains all of the 1394 Software Framework routines called
33 #include <sys/sysmacros.h>
36 #include <sys/sunddi.h>
37 #include <sys/types.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 -
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.
72 t1394_attach(dev_info_t
*dip
, int version
, uint_t flags
,
73 t1394_attachinfo_t
*attachinfo
, t1394_handle_t
*t1394_hdl
)
76 s1394_target_t
*target
;
82 ASSERT(t1394_hdl
!= NULL
);
83 ASSERT(attachinfo
!= NULL
);
87 if (version
!= T1394_VERSION_V1
) {
91 hal
= s1394_dip_to_hal(ddi_get_parent(dip
));
96 ASSERT(MUTEX_NOT_HELD(&hal
->topology_tree_mutex
));
98 hp_node
= ddi_prop_exists(DDI_DEV_T_ANY
, dip
, DDI_PROP_DONTPASS
,
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
);
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
;
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
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.
196 t1394_detach(t1394_handle_t
*t1394_hdl
, uint_t flags
)
198 s1394_target_t
*target
;
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
;
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
;
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
);
244 kmem_free(target
, sizeof (s1394_target_t
));
248 return (DDI_SUCCESS
);
252 * Function: t1394_alloc_cmd()
253 * Input(s): t1394_hdl The target "handle" returned by
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
)
272 s1394_target_t
*target
;
273 s1394_cmd_priv_t
*s_priv
;
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
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.
338 t1394_free_cmd(t1394_handle_t t1394_hdl
, uint_t flags
, cmd1394_cmd_t
**cmdp
)
341 s1394_target_t
*target
;
342 s1394_cmd_priv_t
*s_priv
;
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
;
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 */
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
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
408 t1394_read(t1394_handle_t t1394_hdl
, cmd1394_cmd_t
*cmd
)
411 s1394_target_t
*target
;
412 s1394_cmd_priv_t
*s_priv
;
413 s1394_hal_state_t state
;
417 ASSERT(t1394_hdl
!= 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
;
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
);
524 /* Block (if necessary) */
525 goto 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
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
547 t1394_write(t1394_handle_t t1394_hdl
, cmd1394_cmd_t
*cmd
)
550 s1394_target_t
*target
;
551 s1394_cmd_priv_t
*s_priv
;
552 s1394_hal_state_t state
;
556 ASSERT(t1394_hdl
!= 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
);
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
);
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
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
701 t1394_lock(t1394_handle_t t1394_hdl
, cmd1394_cmd_t
*cmd
)
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
;
711 ASSERT(t1394_hdl
!= 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
);
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
);
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
);
793 cmd
->cmd_result
= CMD1394_EINVALID_COMMAND
;
802 * Function: t1394_alloc_addr()
803 * Input(s): t1394_hdl The target "handle" returned by
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
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
826 t1394_alloc_addr(t1394_handle_t t1394_hdl
, t1394_alloc_addr_t
*addr_allocp
,
827 uint_t flags
, int *result
)
830 s1394_target_t
*target
;
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
);
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
);
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
);
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
,
915 if (err
!= DDI_SUCCESS
) {
916 *result
= T1394_EALLOC_ADDR
;
917 /* kstats - addr alloc failures */
918 hal
->hal_kstats
->addr_alloc_fail
++;
920 *result
= T1394_NOERROR
;
924 err
= s1394_claim_addr_blk((s1394_hal_t
*)target
->on_hal
,
926 if (err
!= DDI_SUCCESS
) {
927 *result
= T1394_EALLOC_ADDR
;
928 /* kstats - addr alloc failures */
929 hal
->hal_kstats
->addr_alloc_fail
++;
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
);
947 * Function: t1394_free_addr()
948 * Input(s): t1394_hdl The target "handle" returned by
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().
962 t1394_free_addr(t1394_handle_t t1394_hdl
, t1394_addr_handle_t
*addr_hdl
,
965 s1394_addr_space_blk_t
*curr_blk
;
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
);
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
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.
1020 t1394_recv_request_done(t1394_handle_t t1394_hdl
, cmd1394_cmd_t
*resp
,
1024 s1394_cmd_priv_t
*s_priv
;
1025 h1394_cmd_priv_t
*h_priv
;
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
)) {
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
)))
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
,
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
;
1087 mblk_too_small
= B_TRUE
;
1089 if (curr_blk
== NULL
) {
1091 * Free the command - Pass it back
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
) {
1102 (curr_blk
->b_wptr
- curr_blk
->b_rptr
);
1104 if (msgb_len
>= size
) {
1105 mblk_too_small
= B_FALSE
;
1108 curr_blk
= curr_blk
->b_cont
;
1111 if (mblk_too_small
== B_TRUE
) {
1113 * Free the command - Pass it back
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
);
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
);
1131 return (DDI_FAILURE
);
1137 * Function: t1394_fcp_register_controller()
1138 * Input(s): t1394_hdl The target "handle" returned by
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
1154 t1394_fcp_register_controller(t1394_handle_t t1394_hdl
, t1394_fcp_evts_t
*evts
,
1159 ASSERT(t1394_hdl
!= NULL
);
1161 result
= s1394_fcp_register_ctl((s1394_target_t
*)t1394_hdl
, evts
);
1167 * Function: t1394_fcp_unregister_controller()
1168 * Input(s): t1394_hdl The target "handle" returned by
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
1179 t1394_fcp_unregister_controller(t1394_handle_t t1394_hdl
)
1183 ASSERT(t1394_hdl
!= NULL
);
1185 result
= s1394_fcp_unregister_ctl((s1394_target_t
*)t1394_hdl
);
1191 * Function: t1394_fcp_register_target()
1192 * Input(s): t1394_hdl The target "handle" returned by
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
1208 t1394_fcp_register_target(t1394_handle_t t1394_hdl
, t1394_fcp_evts_t
*evts
,
1213 ASSERT(t1394_hdl
!= NULL
);
1215 result
= s1394_fcp_register_tgt((s1394_target_t
*)t1394_hdl
, evts
);
1221 * Function: t1394_fcp_unregister_target()
1222 * Input(s): t1394_hdl The target "handle" returned by
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
1233 t1394_fcp_unregister_target(t1394_handle_t t1394_hdl
)
1237 ASSERT(t1394_hdl
!= NULL
);
1239 result
= s1394_fcp_unregister_tgt((s1394_target_t
*)t1394_hdl
);
1245 * Function: t1394_cmp_register()
1246 * Input(s): t1394_hdl The target "handle" returned by
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
1260 t1394_cmp_register(t1394_handle_t t1394_hdl
, t1394_cmp_evts_t
*evts
,
1265 ASSERT(t1394_hdl
!= NULL
);
1267 result
= s1394_cmp_register((s1394_target_t
*)t1394_hdl
, evts
);
1273 * Function: t1394_cmp_unregister()
1274 * Input(s): t1394_hdl The target "handle" returned by
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
1287 t1394_cmp_unregister(t1394_handle_t t1394_hdl
)
1291 ASSERT(t1394_hdl
!= NULL
);
1293 result
= s1394_cmp_unregister((s1394_target_t
*)t1394_hdl
);
1299 * Function: t1394_cmp_read()
1300 * Input(s): t1394_hdl The target "handle" returned by
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
)
1316 ASSERT(t1394_hdl
!= NULL
);
1318 result
= s1394_cmp_read((s1394_target_t
*)t1394_hdl
, reg
, valp
);
1324 * Function: t1394_cmp_cas()
1325 * Input(s): t1394_hdl The target "handle" returned by
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
)
1344 ASSERT(t1394_hdl
!= NULL
);
1346 result
= s1394_cmp_cas((s1394_target_t
*)t1394_hdl
, reg
, arg_val
,
1353 * Function: t1394_alloc_isoch_single()
1354 * Input(s): t1394_hdl The target "handle" returned by
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
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
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.
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
)
1383 s1394_isoch_cec_t
*cec_new
;
1384 t1394_join_isochinfo_t jii
;
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
|
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 */
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
) {
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 */
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 */
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
1525 * t1394_single_hdl The isoch "handle" return by
1526 * t1394_alloc_isoch_single()
1527 * flags The flags parameter is unused (for now)
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().
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
;
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 */
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 */
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 */
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
1587 * props The structure used to set up the
1588 * overall characteristics of for
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
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
)
1605 s1394_isoch_cec_t
*cec_new
;
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 */
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
|
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
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.
1695 t1394_free_isoch_cec(t1394_handle_t t1394_hdl
, uint_t flags
,
1696 t1394_isoch_cec_handle_t
*t1394_isoch_cec_hdl
)
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
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
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.
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
)
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
;
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
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
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.
1906 t1394_leave_isoch_cec(t1394_handle_t t1394_hdl
,
1907 t1394_isoch_cec_handle_t t1394_isoch_cec_hdl
, uint_t flags
)
1910 s1394_isoch_cec_t
*cec_curr
;
1911 s1394_isoch_cec_member_t
*member_curr
;
1912 s1394_isoch_cec_member_t
*member_temp
;
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 */
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
;
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
);
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
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
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()
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
)
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
;
2032 uint_t bw_alloc_units
;
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
)
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
,
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 */
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
)
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
,
2143 ret
= s1394_channel_alloc(hal
,
2144 try_chnl
, generation
,
2145 S1394_CHANNEL_ALLOC_LO
, &old_chnl
,
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
))
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
)
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
,
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
) {
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
)
2198 else if (err
== CMD1394_EBUSRESET
)
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
;
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
;
2228 while (member_curr
!= NULL
) {
2229 if (member_curr
->isoch_cec_evts
.setup_target
!= NULL
) {
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
|
2258 /* Unlock the Isoch CEC member list */
2259 mutex_exit(&cec_curr
->isoch_cec_mutex
);
2261 /* Return DDI_FAILURE if any targets failed setup */
2263 return (DDI_FAILURE
);
2266 return (DDI_SUCCESS
);
2270 * Function: t1394_start_isoch_cec()
2271 * Input(s): t1394_hdl The target "handle" returned by
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
2279 * DDI_FAILURE One or more start_target() callbacks
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.
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
;
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
;
2333 while (member_curr
!= NULL
) {
2334 if (member_curr
->isoch_cec_evts
.start_target
!= NULL
) {
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
)
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
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
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()
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
) {
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
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
2479 * DDI_FAILURE Target failed to tear down the
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.
2491 t1394_teardown_isoch_cec(t1394_handle_t t1394_hdl
,
2492 t1394_isoch_cec_handle_t t1394_isoch_cec_hdl
, uint_t flags
)
2495 s1394_isoch_cec_t
*cec_curr
;
2496 s1394_isoch_cec_member_t
*member_curr
;
2498 uint32_t old_chnl_mask
;
2499 uint_t bw_alloc_units
;
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
;
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
);
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
;
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
) {
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
2652 * idi This structure contains information
2653 * for configuring the data flow for
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
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
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
)
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
;
2712 * Function: t1394_free_isoch_dma()
2713 * Input(s): t1394_hdl The target "handle" returned by
2715 * flags The flags parameter is unused (for now)
2716 * t1394_idma_hdl The IDMA "handle" returned by
2717 * t1394_alloc_isoch_dma()
2721 * Description: t1394_free_isoch_dma() is used to free all DMA resources
2722 * allocated for the isoch stream associated with t1394_idma_hdl.
2726 t1394_free_isoch_dma(t1394_handle_t t1394_hdl
, uint_t flags
,
2727 t1394_isoch_dma_handle_t
*t1394_idma_hdl
)
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
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
2758 * Description: t1394_start_isoch_dma() is used to start DMA for the isoch
2759 * stream associated with t1394_idma_hdl.
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
,
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
);
2785 * Function: t1394_stop_isoch_dma()
2786 * Input(s): t1394_hdl The target "handle" returned by
2788 * t1394_idma_hdl The IDMA "handle" returned by
2789 * t1394_alloc_isoch_dma()
2790 * flags The flags parameter is unused (for now)
2794 * Description: t1394_stop_isoch_dma() is used to stop DMA for the isoch
2795 * stream associated with t1394_idma_hdl.
2799 t1394_stop_isoch_dma(t1394_handle_t t1394_hdl
,
2800 t1394_isoch_dma_handle_t t1394_idma_hdl
, uint_t flags
)
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
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
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().
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
,
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
);
2857 * Function: t1394_initiate_bus_reset()
2858 * Input(s): t1394_hdl The target "handle" returned by
2860 * flags The flags parameter is unused (for now)
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.
2870 t1394_initiate_bus_reset(t1394_handle_t t1394_hdl
, uint_t flags
)
2875 ASSERT(t1394_hdl
!= NULL
);
2877 /* Find the HAL this target resides on */
2878 hal
= ((s1394_target_t
*)t1394_hdl
)->on_hal
;
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
) {
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
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
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.
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
)
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
);
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
2962 * Description: t1394_CRC16() implements ISO/IEC 13213:1994, ANSI/IEEE Std
2963 * 1212, 1994 - 8.1.5.
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 */
2973 ret
= s1394_CRC16((uint_t
*)d
, (uint_t
)crc_length
);
2979 * Function: t1394_add_cfgrom_entry()
2980 * Input(s): t1394_hdl The target "handle" returned by
2982 * cfgrom_entryinfo This structure holds the cfgrom key,
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
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).
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
)
3004 s1394_target_t
*target
;
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 */
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
);
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));
3060 mutex_exit(&hal
->local_config_rom_mutex
);
3067 * Function: t1394_rem_cfgrom_entry()
3068 * Input(s): t1394_hdl The target "handle" returned by
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
3077 * Description: t1394_rem_cfgrom_entry() is used to remove a previously added
3078 * Config ROM entry (indicated by t1394_cfgrom_hdl).
3082 t1394_rem_cfgrom_entry(t1394_handle_t t1394_hdl
, uint_t flags
,
3083 t1394_cfgrom_handle_t
*t1394_cfgrom_hdl
, int *result
)
3086 s1394_target_t
*target
;
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
,
3107 if (ret
!= DDI_SUCCESS
) {
3108 mutex_exit(&hal
->local_config_rom_mutex
);
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));
3120 mutex_exit(&hal
->local_config_rom_mutex
);
3127 * Function: t1394_get_targetinfo()
3128 * Input(s): t1394_hdl The target "handle" returned by
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.
3142 t1394_get_targetinfo(t1394_handle_t t1394_hdl
, uint_t bus_generation
,
3143 uint_t flags
, t1394_targetinfo_t
*targetinfo
)
3146 s1394_target_t
*target
;
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
3175 if (((target
->target_state
& S1394_TARG_GONE
) != 0) ||
3176 (target
->on_node
== NULL
)) {
3177 targetinfo
->target_nodeID
= T1394_INVALID_NODEID
;
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
);