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
);
85 TNF_PROBE_0_DEBUG(t1394_attach_enter
, S1394_TNF_SL_HOTPLUG_STACK
, "");
89 if (version
!= T1394_VERSION_V1
) {
90 TNF_PROBE_1(t1394_attach_error
, S1394_TNF_SL_HOTPLUG_ERROR
, "",
91 tnf_string
, msg
, "Invalid version");
92 TNF_PROBE_0_DEBUG(t1394_attach_exit
,
93 S1394_TNF_SL_HOTPLUG_STACK
, "");
97 hal
= s1394_dip_to_hal(ddi_get_parent(dip
));
99 TNF_PROBE_1(t1394_attach_error
, S1394_TNF_SL_HOTPLUG_ERROR
, "",
100 tnf_string
, msg
, "No parent dip found for target");
101 TNF_PROBE_0_DEBUG(t1394_attach_exit
,
102 S1394_TNF_SL_HOTPLUG_STACK
, "");
103 return (DDI_FAILURE
);
106 ASSERT(MUTEX_NOT_HELD(&hal
->topology_tree_mutex
));
108 hp_node
= ddi_prop_exists(DDI_DEV_T_ANY
, dip
, DDI_PROP_DONTPASS
,
111 /* Allocate space for s1394_target_t */
112 target
= kmem_zalloc(sizeof (s1394_target_t
), KM_SLEEP
);
114 mutex_enter(&hal
->topology_tree_mutex
);
116 target
->target_version
= version
;
118 /* Copy in the params */
119 target
->target_dip
= dip
;
120 target
->on_hal
= hal
;
122 /* Place the target on the appropriate node */
123 target
->on_node
= NULL
;
125 rw_enter(&target
->on_hal
->target_list_rwlock
, RW_WRITER
);
127 s1394_add_target_to_node(target
);
129 * on_node can be NULL if the node got unplugged
130 * while the target driver is in its attach routine.
132 if (target
->on_node
== NULL
) {
133 s1394_remove_target_from_node(target
);
134 rw_exit(&target
->on_hal
->target_list_rwlock
);
135 mutex_exit(&hal
->topology_tree_mutex
);
136 kmem_free(target
, sizeof (s1394_target_t
));
137 TNF_PROBE_1(t1394_attach_error
,
138 S1394_TNF_SL_HOTPLUG_ERROR
, "", tnf_string
, msg
,
140 TNF_PROBE_0_DEBUG(t1394_attach_exit
,
141 S1394_TNF_SL_HOTPLUG_STACK
, "");
142 return (DDI_FAILURE
);
145 target
->target_state
= S1394_TARG_HP_NODE
;
146 if (S1394_NODE_BUS_PWR_CONSUMER(target
->on_node
) == B_TRUE
)
147 target
->target_state
|= S1394_TARG_BUS_PWR_CONSUMER
;
150 /* Return the current generation */
151 attachinfo
->localinfo
.bus_generation
= target
->on_hal
->generation_count
;
153 /* Fill in hal node id */
154 attachinfo
->localinfo
.local_nodeID
= target
->on_hal
->node_id
;
156 /* Give the target driver the iblock_cookie */
157 attachinfo
->iblock_cookie
= target
->on_hal
->halinfo
.hw_interrupt
;
159 /* Give the target driver the attributes */
160 attachinfo
->acc_attr
= target
->on_hal
->halinfo
.acc_attr
;
161 attachinfo
->dma_attr
= target
->on_hal
->halinfo
.dma_attr
;
163 unit_dir
= ddi_prop_get_int(DDI_DEV_T_ANY
, dip
,
164 DDI_PROP_DONTPASS
, "unit-dir-offset", 0);
165 target
->unit_dir
= unit_dir
;
167 /* By default, disable all physical AR requests */
168 target
->physical_arreq_enabled
= 0;
171 /* Get dev_max_payload & current_max_payload */
172 s1394_get_maxpayload(target
, &dev
, &curr
);
173 target
->dev_max_payload
= dev
;
174 target
->current_max_payload
= curr
;
176 /* Add into linked list */
177 if ((target
->on_hal
->target_head
== NULL
) &&
178 (target
->on_hal
->target_tail
== NULL
)) {
179 target
->on_hal
->target_head
= target
;
180 target
->on_hal
->target_tail
= target
;
182 target
->on_hal
->target_tail
->target_next
= target
;
183 target
->target_prev
= target
->on_hal
->target_tail
;
184 target
->on_hal
->target_tail
= target
;
186 rw_exit(&target
->on_hal
->target_list_rwlock
);
188 /* Fill in services layer private info */
189 *t1394_hdl
= (t1394_handle_t
)target
;
191 mutex_exit(&hal
->topology_tree_mutex
);
193 TNF_PROBE_0_DEBUG(t1394_attach_exit
, S1394_TNF_SL_HOTPLUG_STACK
, "");
194 return (DDI_SUCCESS
);
198 * Function: t1394_detach()
199 * Input(s): t1394_hdl The target "handle" returned by
201 * flags The flags parameter is unused (for now)
203 * Output(s): DDI_SUCCESS Target successfully detached
204 * DDI_FAILURE Target failed to detach
206 * Description: t1394_detach() unregisters the target from the 1394 Software
207 * Framework. t1394_detach() can fail if the target has any
208 * allocated commands that haven't been freed.
212 t1394_detach(t1394_handle_t
*t1394_hdl
, uint_t flags
)
214 s1394_target_t
*target
;
217 TNF_PROBE_0_DEBUG(t1394_detach_enter
, S1394_TNF_SL_HOTPLUG_STACK
, "");
219 ASSERT(t1394_hdl
!= NULL
);
221 target
= (s1394_target_t
*)(*t1394_hdl
);
223 ASSERT(target
->on_hal
);
225 mutex_enter(&target
->on_hal
->topology_tree_mutex
);
226 rw_enter(&target
->on_hal
->target_list_rwlock
, RW_WRITER
);
228 /* How many cmds has this target allocated? */
229 num_cmds
= target
->target_num_cmds
;
232 rw_exit(&target
->on_hal
->target_list_rwlock
);
233 mutex_exit(&target
->on_hal
->topology_tree_mutex
);
234 TNF_PROBE_1(t1394_detach_error
, S1394_TNF_SL_HOTPLUG_ERROR
, "",
235 tnf_string
, msg
, "Must free all commands before detach()");
236 TNF_PROBE_0_DEBUG(t1394_detach_exit
,
237 S1394_TNF_SL_HOTPLUG_STACK
, "");
238 return (DDI_FAILURE
);
242 * Remove from linked lists. Topology tree is already locked
243 * so that the node won't go away while we are looking at it.
245 if ((target
->on_hal
->target_head
== target
) &&
246 (target
->on_hal
->target_tail
== target
)) {
247 target
->on_hal
->target_head
= NULL
;
248 target
->on_hal
->target_tail
= NULL
;
250 if (target
->target_prev
)
251 target
->target_prev
->target_next
= target
->target_next
;
252 if (target
->target_next
)
253 target
->target_next
->target_prev
= target
->target_prev
;
254 if (target
->on_hal
->target_head
== target
)
255 target
->on_hal
->target_head
= target
->target_next
;
256 if (target
->on_hal
->target_tail
== target
)
257 target
->on_hal
->target_tail
= target
->target_prev
;
260 s1394_remove_target_from_node(target
);
261 rw_exit(&target
->on_hal
->target_list_rwlock
);
263 mutex_exit(&target
->on_hal
->topology_tree_mutex
);
266 kmem_free(target
, sizeof (s1394_target_t
));
270 TNF_PROBE_0_DEBUG(t1394_detach_exit
, S1394_TNF_SL_HOTPLUG_STACK
, "");
271 return (DDI_SUCCESS
);
275 * Function: t1394_alloc_cmd()
276 * Input(s): t1394_hdl The target "handle" returned by
278 * flags The flags parameter is described below
280 * Output(s): cmdp Pointer to the newly allocated command
282 * Description: t1394_alloc_cmd() allocates a command for use with the
283 * t1394_read(), t1394_write(), or t1394_lock() interfaces
284 * of the 1394 Software Framework. By default, t1394_alloc_cmd()
285 * may sleep while allocating memory for the command structure.
286 * If this is undesirable, the target may set the
287 * T1394_ALLOC_CMD_NOSLEEP bit in the flags parameter. Also,
288 * this call may fail because a target driver has already
289 * allocated MAX_NUMBER_ALLOC_CMDS commands.
292 t1394_alloc_cmd(t1394_handle_t t1394_hdl
, uint_t flags
, cmd1394_cmd_t
**cmdp
)
295 s1394_target_t
*target
;
296 s1394_cmd_priv_t
*s_priv
;
299 TNF_PROBE_0_DEBUG(t1394_alloc_cmd_enter
, S1394_TNF_SL_ATREQ_STACK
, "");
301 ASSERT(t1394_hdl
!= NULL
);
303 target
= (s1394_target_t
*)t1394_hdl
;
305 /* Find the HAL this target resides on */
306 hal
= target
->on_hal
;
308 rw_enter(&hal
->target_list_rwlock
, RW_WRITER
);
310 /* How many cmds has this target allocated? */
311 num_cmds
= target
->target_num_cmds
;
313 if (num_cmds
>= MAX_NUMBER_ALLOC_CMDS
) {
314 rw_exit(&hal
->target_list_rwlock
);
315 TNF_PROBE_1(t1394_alloc_cmd_error
, S1394_TNF_SL_ATREQ_ERROR
,
316 "", tnf_string
, msg
, "Attempted to alloc > "
317 "MAX_NUMBER_ALLOC_CMDS");
318 TNF_PROBE_0_DEBUG(t1394_alloc_cmd_exit
,
319 S1394_TNF_SL_ATREQ_STACK
, "");
320 /* kstats - cmd alloc failures */
321 hal
->hal_kstats
->cmd_alloc_fail
++;
322 return (DDI_FAILURE
);
325 /* Increment the number of cmds this target has allocated? */
326 target
->target_num_cmds
= num_cmds
+ 1;
328 if (s1394_alloc_cmd(hal
, flags
, cmdp
) != DDI_SUCCESS
) {
329 target
->target_num_cmds
= num_cmds
; /* Undo increment */
330 rw_exit(&hal
->target_list_rwlock
);
331 TNF_PROBE_1(t1394_alloc_cmd_error
, S1394_TNF_SL_ATREQ_ERROR
, "",
332 tnf_string
, msg
, "Failed to allocate command structure");
333 TNF_PROBE_0_DEBUG(t1394_alloc_cmd_exit
,
334 S1394_TNF_SL_ATREQ_STACK
, "");
335 /* kstats - cmd alloc failures */
336 hal
->hal_kstats
->cmd_alloc_fail
++;
337 return (DDI_FAILURE
);
340 rw_exit(&hal
->target_list_rwlock
);
342 /* Get the Services Layer private area */
343 s_priv
= S1394_GET_CMD_PRIV(*cmdp
);
345 /* Initialize the command's blocking mutex */
346 mutex_init(&s_priv
->blocking_mutex
, NULL
, MUTEX_DRIVER
,
347 hal
->halinfo
.hw_interrupt
);
349 /* Initialize the command's blocking condition variable */
350 cv_init(&s_priv
->blocking_cv
, NULL
, CV_DRIVER
, NULL
);
352 TNF_PROBE_0_DEBUG(t1394_alloc_cmd_exit
, S1394_TNF_SL_ATREQ_STACK
, "");
353 return (DDI_SUCCESS
);
357 * Function: t1394_free_cmd()
358 * Input(s): t1394_hdl The target "handle" returned by
360 * flags The flags parameter is unused (for now)
361 * cmdp Pointer to the command to be freed
363 * Output(s): DDI_SUCCESS Target successfully freed command
364 * DDI_FAILURE Target failed to free command
366 * Description: t1394_free_cmd() attempts to free a command that has previously
367 * been allocated by the target driver. It is possible for
368 * t1394_free_cmd() to fail because the command is currently
369 * in-use by the 1394 Software Framework.
373 t1394_free_cmd(t1394_handle_t t1394_hdl
, uint_t flags
, cmd1394_cmd_t
**cmdp
)
376 s1394_target_t
*target
;
377 s1394_cmd_priv_t
*s_priv
;
380 TNF_PROBE_0_DEBUG(t1394_free_cmd_enter
, S1394_TNF_SL_ATREQ_STACK
, "");
382 ASSERT(t1394_hdl
!= NULL
);
384 target
= (s1394_target_t
*)t1394_hdl
;
386 /* Find the HAL this target resides on */
387 hal
= target
->on_hal
;
389 rw_enter(&hal
->target_list_rwlock
, RW_WRITER
);
391 /* How many cmds has this target allocated? */
392 num_cmds
= target
->target_num_cmds
;
395 rw_exit(&hal
->target_list_rwlock
);
396 TNF_PROBE_2(t1394_free_cmd_error
, S1394_TNF_SL_ATREQ_ERROR
, "",
397 tnf_string
, msg
, "No commands left to be freed "
398 "(num_cmds <= 0)", tnf_uint
, num_cmds
, num_cmds
);
399 TNF_PROBE_0_DEBUG(t1394_free_cmd_exit
,
400 S1394_TNF_SL_ATREQ_STACK
, "");
401 ASSERT(num_cmds
!= 0);
402 return (DDI_FAILURE
);
405 /* Get the Services Layer private area */
406 s_priv
= S1394_GET_CMD_PRIV(*cmdp
);
408 /* Check that command isn't in use */
409 if (s_priv
->cmd_in_use
== B_TRUE
) {
410 rw_exit(&hal
->target_list_rwlock
);
411 TNF_PROBE_1(t1394_free_cmd_error
, S1394_TNF_SL_ATREQ_ERROR
, "",
412 tnf_string
, msg
, "Attempted to free an in-use command");
413 TNF_PROBE_0_DEBUG(t1394_free_cmd_exit
,
414 S1394_TNF_SL_ATREQ_STACK
, "");
415 ASSERT(s_priv
->cmd_in_use
== B_FALSE
);
416 return (DDI_FAILURE
);
419 /* Decrement the number of cmds this target has allocated */
420 target
->target_num_cmds
--;
422 rw_exit(&hal
->target_list_rwlock
);
424 /* Destroy the command's blocking condition variable */
425 cv_destroy(&s_priv
->blocking_cv
);
427 /* Destroy the command's blocking mutex */
428 mutex_destroy(&s_priv
->blocking_mutex
);
430 kmem_cache_free(hal
->hal_kmem_cachep
, *cmdp
);
432 /* Command pointer is set to NULL before returning */
435 /* kstats - number of cmd frees */
436 hal
->hal_kstats
->cmd_free
++;
438 TNF_PROBE_0_DEBUG(t1394_free_cmd_exit
, S1394_TNF_SL_ATREQ_STACK
, "");
439 return (DDI_SUCCESS
);
443 * Function: t1394_read()
444 * Input(s): t1394_hdl The target "handle" returned by
446 * cmd Pointer to the command to send
448 * Output(s): DDI_SUCCESS Target successful sent the command
449 * DDI_FAILURE Target failed to send command
451 * Description: t1394_read() attempts to send an asynchronous read request
455 t1394_read(t1394_handle_t t1394_hdl
, cmd1394_cmd_t
*cmd
)
458 s1394_target_t
*target
;
459 s1394_cmd_priv_t
*s_priv
;
460 s1394_hal_state_t state
;
464 TNF_PROBE_0_DEBUG(t1394_read_enter
, S1394_TNF_SL_ATREQ_STACK
, "");
466 ASSERT(t1394_hdl
!= NULL
);
469 /* Get the Services Layer private area */
470 s_priv
= S1394_GET_CMD_PRIV(cmd
);
472 /* Is this command currently in use? */
473 if (s_priv
->cmd_in_use
== B_TRUE
) {
474 TNF_PROBE_1(t1394_read_error
, S1394_TNF_SL_ATREQ_ERROR
, "",
475 tnf_string
, msg
, "Attempted to resend an in-use command");
476 TNF_PROBE_0_DEBUG(t1394_read_exit
, S1394_TNF_SL_ATREQ_STACK
,
478 ASSERT(s_priv
->cmd_in_use
== B_FALSE
);
479 return (DDI_FAILURE
);
482 target
= (s1394_target_t
*)t1394_hdl
;
484 /* Set-up the destination of the command */
485 to_hal
= target
->on_hal
;
487 /* No status (default) */
488 cmd
->cmd_result
= CMD1394_NOSTATUS
;
490 /* Check for proper command type */
491 if ((cmd
->cmd_type
!= CMD1394_ASYNCH_RD_QUAD
) &&
492 (cmd
->cmd_type
!= CMD1394_ASYNCH_RD_BLOCK
)) {
493 cmd
->cmd_result
= CMD1394_EINVALID_COMMAND
;
494 TNF_PROBE_1(t1394_read_error
, S1394_TNF_SL_ATREQ_ERROR
, "",
495 tnf_string
, msg
, "Invalid command type specified");
496 TNF_PROBE_0_DEBUG(t1394_read_exit
,
497 S1394_TNF_SL_ATREQ_STACK
, "");
498 return (DDI_FAILURE
);
501 /* Is this a blocking command on interrupt stack? */
502 if ((cmd
->cmd_options
& CMD1394_BLOCKING
) &&
503 (servicing_interrupt())) {
504 cmd
->cmd_result
= CMD1394_EINVALID_CONTEXT
;
505 TNF_PROBE_1(t1394_read_error
, S1394_TNF_SL_ATREQ_ERROR
, "",
506 tnf_string
, msg
, "Tried to use CMD1394_BLOCKING in "
508 TNF_PROBE_0_DEBUG(t1394_read_exit
,
509 S1394_TNF_SL_ATREQ_STACK
, "");
510 return (DDI_FAILURE
);
513 mutex_enter(&to_hal
->topology_tree_mutex
);
514 state
= to_hal
->hal_state
;
515 if (state
!= S1394_HAL_NORMAL
) {
516 ret
= s1394_HAL_asynch_error(to_hal
, cmd
, state
);
517 if (ret
!= CMD1394_CMDSUCCESS
) {
518 cmd
->cmd_result
= ret
;
519 mutex_exit(&to_hal
->topology_tree_mutex
);
520 return (DDI_FAILURE
);
524 ret
= s1394_setup_asynch_command(to_hal
, target
, cmd
,
525 S1394_CMD_READ
, &err
);
527 /* Command has now been put onto the queue! */
528 if (ret
!= DDI_SUCCESS
) {
529 /* Copy error code into result */
530 cmd
->cmd_result
= err
;
531 mutex_exit(&to_hal
->topology_tree_mutex
);
532 TNF_PROBE_1(t1394_read_error
, S1394_TNF_SL_ATREQ_ERROR
, "",
533 tnf_string
, msg
, "Failed in s1394_setup_asynch_command()");
534 TNF_PROBE_0_DEBUG(t1394_read_exit
,
535 S1394_TNF_SL_ATREQ_STACK
, "");
536 return (DDI_FAILURE
);
540 * If this command was sent during a bus reset,
541 * then put it onto the pending Q.
543 if (state
== S1394_HAL_RESET
) {
544 /* Remove cmd from outstanding request Q */
545 s1394_remove_q_asynch_cmd(to_hal
, cmd
);
546 /* Are we on the bus reset event stack? */
547 if (s1394_on_br_thread(to_hal
) == B_TRUE
) {
548 /* Blocking commands are not allowed */
549 if (cmd
->cmd_options
& CMD1394_BLOCKING
) {
550 mutex_exit(&to_hal
->topology_tree_mutex
);
551 s_priv
->cmd_in_use
= B_FALSE
;
552 cmd
->cmd_result
= CMD1394_EINVALID_CONTEXT
;
553 TNF_PROBE_1(t1394_read_error
,
554 S1394_TNF_SL_ATREQ_ERROR
, "", tnf_string
,
555 msg
, "CMD1394_BLOCKING in bus reset "
557 TNF_PROBE_0_DEBUG(t1394_read_exit
,
558 S1394_TNF_SL_ATREQ_STACK
, "");
559 return (DDI_FAILURE
);
563 s1394_pending_q_insert(to_hal
, cmd
, S1394_PENDING_Q_FRONT
);
564 mutex_exit(&to_hal
->topology_tree_mutex
);
566 /* Block (if necessary) */
567 goto block_on_asynch_cmd
;
569 mutex_exit(&to_hal
->topology_tree_mutex
);
571 /* Send the command out */
572 ret
= s1394_xfer_asynch_command(to_hal
, cmd
, &err
);
574 if (ret
!= DDI_SUCCESS
) {
575 if (err
== CMD1394_ESTALE_GENERATION
) {
576 /* Remove cmd from outstanding request Q */
577 s1394_remove_q_asynch_cmd(to_hal
, cmd
);
578 s1394_pending_q_insert(to_hal
, cmd
,
579 S1394_PENDING_Q_FRONT
);
581 /* Block (if necessary) */
582 goto block_on_asynch_cmd
;
585 /* Remove cmd from outstanding request Q */
586 s1394_remove_q_asynch_cmd(to_hal
, cmd
);
588 s_priv
->cmd_in_use
= B_FALSE
;
590 /* Copy error code into result */
591 cmd
->cmd_result
= err
;
593 TNF_PROBE_1(t1394_read_error
, S1394_TNF_SL_ATREQ_ERROR
,
594 "", tnf_string
, msg
, "Failed in "
595 "s1394_xfer_asynch_command()");
596 TNF_PROBE_0_DEBUG(t1394_read_exit
,
597 S1394_TNF_SL_ATREQ_STACK
, "");
598 return (DDI_FAILURE
);
601 /* Block (if necessary) */
602 goto block_on_asynch_cmd
;
606 s1394_block_on_asynch_cmd(cmd
);
608 TNF_PROBE_0_DEBUG(t1394_read_exit
,
609 S1394_TNF_SL_ATREQ_STACK
, "");
610 return (DDI_SUCCESS
);
614 * Function: t1394_write()
615 * Input(s): t1394_hdl The target "handle" returned by
617 * cmd Pointer to the command to send
619 * Output(s): DDI_SUCCESS Target successful sent the command
620 * DDI_FAILURE Target failed to send command
622 * Description: t1394_write() attempts to send an asynchronous write request
626 t1394_write(t1394_handle_t t1394_hdl
, cmd1394_cmd_t
*cmd
)
629 s1394_target_t
*target
;
630 s1394_cmd_priv_t
*s_priv
;
631 s1394_hal_state_t state
;
635 TNF_PROBE_0_DEBUG(t1394_write_enter
, S1394_TNF_SL_ATREQ_STACK
, "");
637 ASSERT(t1394_hdl
!= NULL
);
640 /* Get the Services Layer private area */
641 s_priv
= S1394_GET_CMD_PRIV(cmd
);
643 /* Is this command currently in use? */
644 if (s_priv
->cmd_in_use
== B_TRUE
) {
645 TNF_PROBE_1(t1394_write_error
, S1394_TNF_SL_ATREQ_ERROR
, "",
646 tnf_string
, msg
, "Attempted to resend an in-use command");
647 TNF_PROBE_0_DEBUG(t1394_write_exit
, S1394_TNF_SL_ATREQ_STACK
,
649 ASSERT(s_priv
->cmd_in_use
== B_FALSE
);
650 return (DDI_FAILURE
);
653 target
= (s1394_target_t
*)t1394_hdl
;
655 /* Set-up the destination of the command */
656 to_hal
= target
->on_hal
;
658 /* Is this an FA request? */
659 if (s_priv
->cmd_ext_type
== S1394_CMD_EXT_FA
) {
660 if (S1394_IS_CMD_FCP(s_priv
) &&
661 (s1394_fcp_write_check_cmd(cmd
) != DDI_SUCCESS
)) {
662 TNF_PROBE_0_DEBUG(t1394_write_exit
,
663 S1394_TNF_SL_ATREQ_STACK
, "");
664 return (DDI_FAILURE
);
666 s1394_fa_convert_cmd(to_hal
, cmd
);
669 /* No status (default) */
670 cmd
->cmd_result
= CMD1394_NOSTATUS
;
672 /* Check for proper command type */
673 if ((cmd
->cmd_type
!= CMD1394_ASYNCH_WR_QUAD
) &&
674 (cmd
->cmd_type
!= CMD1394_ASYNCH_WR_BLOCK
)) {
675 cmd
->cmd_result
= CMD1394_EINVALID_COMMAND
;
676 s1394_fa_check_restore_cmd(to_hal
, cmd
);
677 TNF_PROBE_1(t1394_write_error
, S1394_TNF_SL_ATREQ_ERROR
, "",
678 tnf_string
, msg
, "Invalid command type specified");
679 TNF_PROBE_0_DEBUG(t1394_write_exit
, S1394_TNF_SL_ATREQ_STACK
,
681 return (DDI_FAILURE
);
684 /* Is this a blocking command on interrupt stack? */
685 if ((cmd
->cmd_options
& CMD1394_BLOCKING
) &&
686 (servicing_interrupt())) {
687 cmd
->cmd_result
= CMD1394_EINVALID_CONTEXT
;
688 s1394_fa_check_restore_cmd(to_hal
, cmd
);
689 TNF_PROBE_1(t1394_write_error
, S1394_TNF_SL_ATREQ_ERROR
, "",
690 tnf_string
, msg
, "Tried to use CMD1394_BLOCKING in intr "
692 TNF_PROBE_0_DEBUG(t1394_write_exit
, S1394_TNF_SL_ATREQ_STACK
,
694 return (DDI_FAILURE
);
697 mutex_enter(&to_hal
->topology_tree_mutex
);
698 state
= to_hal
->hal_state
;
699 if (state
!= S1394_HAL_NORMAL
) {
700 ret
= s1394_HAL_asynch_error(to_hal
, cmd
, state
);
701 if (ret
!= CMD1394_CMDSUCCESS
) {
702 cmd
->cmd_result
= ret
;
703 mutex_exit(&to_hal
->topology_tree_mutex
);
704 s1394_fa_check_restore_cmd(to_hal
, cmd
);
705 return (DDI_FAILURE
);
709 ret
= s1394_setup_asynch_command(to_hal
, target
, cmd
,
710 S1394_CMD_WRITE
, &err
);
712 /* Command has now been put onto the queue! */
713 if (ret
!= DDI_SUCCESS
) {
714 /* Copy error code into result */
715 cmd
->cmd_result
= err
;
716 mutex_exit(&to_hal
->topology_tree_mutex
);
717 s1394_fa_check_restore_cmd(to_hal
, cmd
);
718 TNF_PROBE_1(t1394_write_error
, S1394_TNF_SL_ATREQ_ERROR
, "",
719 tnf_string
, msg
, "Failed in s1394_setup_asynch_command()");
720 TNF_PROBE_0_DEBUG(t1394_write_exit
, S1394_TNF_SL_ATREQ_STACK
,
722 return (DDI_FAILURE
);
726 * If this command was sent during a bus reset,
727 * then put it onto the pending Q.
729 if (state
== S1394_HAL_RESET
) {
730 /* Remove cmd from outstanding request Q */
731 s1394_remove_q_asynch_cmd(to_hal
, cmd
);
732 /* Are we on the bus reset event stack? */
733 if (s1394_on_br_thread(to_hal
) == B_TRUE
) {
734 /* Blocking commands are not allowed */
735 if (cmd
->cmd_options
& CMD1394_BLOCKING
) {
736 mutex_exit(&to_hal
->topology_tree_mutex
);
737 s_priv
->cmd_in_use
= B_FALSE
;
738 cmd
->cmd_result
= CMD1394_EINVALID_CONTEXT
;
739 s1394_fa_check_restore_cmd(to_hal
, cmd
);
740 TNF_PROBE_1(t1394_write_error
,
741 S1394_TNF_SL_ATREQ_ERROR
, "", tnf_string
,
742 msg
, "CMD1394_BLOCKING in bus reset cntxt");
743 TNF_PROBE_0_DEBUG(t1394_write_exit
,
744 S1394_TNF_SL_ATREQ_STACK
, "");
745 return (DDI_FAILURE
);
749 s1394_pending_q_insert(to_hal
, cmd
, S1394_PENDING_Q_FRONT
);
750 mutex_exit(&to_hal
->topology_tree_mutex
);
752 /* Block (if necessary) */
753 s1394_block_on_asynch_cmd(cmd
);
755 TNF_PROBE_0_DEBUG(t1394_write_exit
, S1394_TNF_SL_ATREQ_STACK
,
757 return (DDI_SUCCESS
);
759 mutex_exit(&to_hal
->topology_tree_mutex
);
761 /* Send the command out */
762 ret
= s1394_xfer_asynch_command(to_hal
, cmd
, &err
);
764 if (ret
!= DDI_SUCCESS
) {
765 if (err
== CMD1394_ESTALE_GENERATION
) {
766 /* Remove cmd from outstanding request Q */
767 s1394_remove_q_asynch_cmd(to_hal
, cmd
);
768 s1394_pending_q_insert(to_hal
, cmd
,
769 S1394_PENDING_Q_FRONT
);
771 /* Block (if necessary) */
772 s1394_block_on_asynch_cmd(cmd
);
774 TNF_PROBE_0_DEBUG(t1394_write_exit
,
775 S1394_TNF_SL_ATREQ_STACK
, "");
776 return (DDI_SUCCESS
);
778 /* Remove cmd from outstanding request Q */
779 s1394_remove_q_asynch_cmd(to_hal
, cmd
);
781 s_priv
->cmd_in_use
= B_FALSE
;
783 /* Copy error code into result */
784 cmd
->cmd_result
= err
;
786 s1394_fa_check_restore_cmd(to_hal
, cmd
);
787 TNF_PROBE_1(t1394_write_error
,
788 S1394_TNF_SL_ATREQ_ERROR
, "", tnf_string
, msg
,
789 "Failed in s1394_xfer_asynch_command()");
790 TNF_PROBE_0_DEBUG(t1394_write_exit
,
791 S1394_TNF_SL_ATREQ_STACK
, "");
792 return (DDI_FAILURE
);
795 /* Block (if necessary) */
796 s1394_block_on_asynch_cmd(cmd
);
798 TNF_PROBE_0_DEBUG(t1394_write_exit
, S1394_TNF_SL_ATREQ_STACK
,
800 return (DDI_SUCCESS
);
805 * Function: t1394_lock()
806 * Input(s): t1394_hdl The target "handle" returned by
808 * cmd Pointer to the command to send
810 * Output(s): DDI_SUCCESS Target successful sent the command
811 * DDI_FAILURE Target failed to send command
813 * Description: t1394_lock() attempts to send an asynchronous lock request
817 t1394_lock(t1394_handle_t t1394_hdl
, cmd1394_cmd_t
*cmd
)
820 s1394_target_t
*target
;
821 s1394_cmd_priv_t
*s_priv
;
822 s1394_hal_state_t state
;
823 cmd1394_lock_type_t lock_type
;
827 TNF_PROBE_0_DEBUG(t1394_lock_enter
, S1394_TNF_SL_ATREQ_STACK
, "");
829 ASSERT(t1394_hdl
!= NULL
);
832 /* Get the Services Layer private area */
833 s_priv
= S1394_GET_CMD_PRIV(cmd
);
835 /* Is this command currently in use? */
836 if (s_priv
->cmd_in_use
== B_TRUE
) {
837 TNF_PROBE_1(t1394_lock_error
, S1394_TNF_SL_ATREQ_ERROR
, "",
838 tnf_string
, msg
, "Attempted to resend an in-use command");
839 TNF_PROBE_0_DEBUG(t1394_lock_exit
, S1394_TNF_SL_ATREQ_STACK
,
841 ASSERT(s_priv
->cmd_in_use
== B_FALSE
);
842 return (DDI_FAILURE
);
845 target
= (s1394_target_t
*)t1394_hdl
;
847 /* Set-up the destination of the command */
848 to_hal
= target
->on_hal
;
850 mutex_enter(&to_hal
->topology_tree_mutex
);
851 state
= to_hal
->hal_state
;
852 if (state
!= S1394_HAL_NORMAL
) {
853 ret
= s1394_HAL_asynch_error(to_hal
, cmd
, state
);
854 if (ret
!= CMD1394_CMDSUCCESS
) {
855 cmd
->cmd_result
= ret
;
856 mutex_exit(&to_hal
->topology_tree_mutex
);
857 return (DDI_FAILURE
);
860 mutex_exit(&to_hal
->topology_tree_mutex
);
862 /* Check for proper command type */
863 if ((cmd
->cmd_type
!= CMD1394_ASYNCH_LOCK_32
) &&
864 (cmd
->cmd_type
!= CMD1394_ASYNCH_LOCK_64
)) {
865 cmd
->cmd_result
= CMD1394_EINVALID_COMMAND
;
866 TNF_PROBE_1(t1394_lock_error
, S1394_TNF_SL_ATREQ_ERROR
, "",
867 tnf_string
, msg
, "Invalid command type sent to "
869 TNF_PROBE_0_DEBUG(t1394_lock_exit
, S1394_TNF_SL_ATREQ_STACK
,
871 return (DDI_FAILURE
);
874 /* No status (default) */
875 cmd
->cmd_result
= CMD1394_NOSTATUS
;
877 /* Is this a blocking command on interrupt stack? */
878 if ((cmd
->cmd_options
& CMD1394_BLOCKING
) &&
879 (servicing_interrupt())) {
880 cmd
->cmd_result
= CMD1394_EINVALID_CONTEXT
;
881 TNF_PROBE_1(t1394_lock_error
, S1394_TNF_SL_ATREQ_ERROR
, "",
882 tnf_string
, msg
, "Tried to use CMD1394_BLOCKING in intr "
884 TNF_PROBE_0_DEBUG(t1394_lock_exit
, S1394_TNF_SL_ATREQ_STACK
,
886 return (DDI_FAILURE
);
889 if (cmd
->cmd_type
== CMD1394_ASYNCH_LOCK_32
) {
890 lock_type
= cmd
->cmd_u
.l32
.lock_type
;
891 num_retries
= cmd
->cmd_u
.l32
.num_retries
;
892 } else { /* (cmd->cmd_type == CMD1394_ASYNCH_LOCK_64) */
893 lock_type
= cmd
->cmd_u
.l64
.lock_type
;
894 num_retries
= cmd
->cmd_u
.l64
.num_retries
;
897 /* Make sure num_retries is reasonable */
898 ASSERT(num_retries
<= MAX_NUMBER_OF_LOCK_RETRIES
);
901 case CMD1394_LOCK_MASK_SWAP
:
902 case CMD1394_LOCK_FETCH_ADD
:
903 case CMD1394_LOCK_LITTLE_ADD
:
904 case CMD1394_LOCK_BOUNDED_ADD
:
905 case CMD1394_LOCK_WRAP_ADD
:
906 case CMD1394_LOCK_COMPARE_SWAP
:
907 ret
= s1394_compare_swap(to_hal
, target
, cmd
);
910 case CMD1394_LOCK_BIT_AND
:
911 case CMD1394_LOCK_BIT_OR
:
912 case CMD1394_LOCK_BIT_XOR
:
913 case CMD1394_LOCK_INCREMENT
:
914 case CMD1394_LOCK_DECREMENT
:
915 case CMD1394_LOCK_ADD
:
916 case CMD1394_LOCK_SUBTRACT
:
917 case CMD1394_LOCK_THRESH_ADD
:
918 case CMD1394_LOCK_THRESH_SUBTRACT
:
919 case CMD1394_LOCK_CLIP_ADD
:
920 case CMD1394_LOCK_CLIP_SUBTRACT
:
921 ret
= s1394_split_lock_req(to_hal
, target
, cmd
);
925 TNF_PROBE_1(t1394_lock_error
, S1394_TNF_SL_ATREQ_ERROR
, "",
926 tnf_string
, msg
, "Invalid lock_type in command");
927 cmd
->cmd_result
= CMD1394_EINVALID_COMMAND
;
932 TNF_PROBE_0_DEBUG(t1394_lock_exit
, S1394_TNF_SL_ATREQ_STACK
, "");
937 * Function: t1394_alloc_addr()
938 * Input(s): t1394_hdl The target "handle" returned by
940 * addr_allocp The structure used to specify the type,
941 * size, permissions, and callbacks
942 * (if any) for the requested block
943 * of 1394 address space
944 * flags The flags parameter is unused (for now)
946 * Output(s): result Used to pass more specific info back
949 * Description: t1394_alloc_addr() requests that part of the 1394 Address Space
950 * on the local node be set aside for this target driver, and
951 * associated with this address space should be some permissions
952 * and callbacks. If the request is unable to be fulfilled,
953 * t1394_alloc_addr() will return DDI_FAILURE and result will
954 * indicate the reason. T1394_EINVALID_PARAM indicates that the
955 * combination of flags given is invalid, and T1394_EALLOC_ADDR
956 * indicates that the requested type of address space is
961 t1394_alloc_addr(t1394_handle_t t1394_hdl
, t1394_alloc_addr_t
*addr_allocp
,
962 uint_t flags
, int *result
)
965 s1394_target_t
*target
;
970 TNF_PROBE_0_DEBUG(t1394_alloc_addr_enter
, S1394_TNF_SL_ARREQ_STACK
,
973 ASSERT(t1394_hdl
!= NULL
);
974 ASSERT(addr_allocp
!= NULL
);
976 target
= (s1394_target_t
*)t1394_hdl
;
978 /* Find the HAL this target resides on */
979 hal
= target
->on_hal
;
981 /* Get the bounds of the request */
982 addr_lo
= addr_allocp
->aa_address
;
983 addr_hi
= addr_lo
+ addr_allocp
->aa_length
;
985 /* Check combination of flags */
986 if ((addr_allocp
->aa_enable
& T1394_ADDR_RDENBL
) &&
987 (addr_allocp
->aa_evts
.recv_read_request
== NULL
) &&
988 (addr_allocp
->aa_kmem_bufp
== NULL
)) {
989 if ((addr_allocp
->aa_type
!= T1394_ADDR_FIXED
) ||
990 (addr_lo
< hal
->physical_addr_lo
) ||
991 (addr_hi
> hal
->physical_addr_hi
)) {
994 * Reads are enabled, but target doesn't want to
995 * be notified and hasn't given backing store
997 *result
= T1394_EINVALID_PARAM
;
999 TNF_PROBE_1(t1394_alloc_addr_error
,
1000 S1394_TNF_SL_ARREQ_ERROR
, "", tnf_string
, msg
,
1002 "(RDs on, notify off, no backing store)");
1003 TNF_PROBE_0_DEBUG(t1394_alloc_addr_exit
,
1004 S1394_TNF_SL_ARREQ_STACK
, "");
1006 /* kstats - addr alloc failures */
1007 hal
->hal_kstats
->addr_alloc_fail
++;
1008 return (DDI_FAILURE
);
1010 addr_allocp
->aa_enable
&= ~T1394_ADDR_RDENBL
;
1014 if ((addr_allocp
->aa_enable
& T1394_ADDR_WRENBL
) &&
1015 (addr_allocp
->aa_evts
.recv_write_request
== NULL
) &&
1016 (addr_allocp
->aa_kmem_bufp
== NULL
)) {
1017 if ((addr_allocp
->aa_type
!= T1394_ADDR_FIXED
) ||
1018 (addr_lo
< hal
->physical_addr_lo
) ||
1019 (addr_hi
> hal
->physical_addr_hi
)) {
1022 * Writes are enabled, but target doesn't want to
1023 * be notified and hasn't given backing store
1025 *result
= T1394_EINVALID_PARAM
;
1027 TNF_PROBE_1(t1394_alloc_addr_error
,
1028 S1394_TNF_SL_ARREQ_ERROR
, "", tnf_string
, msg
,
1030 "(WRs on, notify off, no backing store)");
1031 TNF_PROBE_0_DEBUG(t1394_alloc_addr_exit
,
1032 S1394_TNF_SL_ARREQ_STACK
, "");
1034 /* kstats - addr alloc failures */
1035 hal
->hal_kstats
->addr_alloc_fail
++;
1036 return (DDI_FAILURE
);
1038 addr_allocp
->aa_enable
&= ~T1394_ADDR_WRENBL
;
1042 if ((addr_allocp
->aa_enable
& T1394_ADDR_LKENBL
) &&
1043 (addr_allocp
->aa_evts
.recv_lock_request
== NULL
) &&
1044 (addr_allocp
->aa_kmem_bufp
== NULL
)) {
1045 if ((addr_allocp
->aa_type
!= T1394_ADDR_FIXED
) ||
1046 (addr_lo
< hal
->physical_addr_lo
) ||
1047 (addr_hi
> hal
->physical_addr_hi
)) {
1050 * Locks are enabled, but target doesn't want to
1051 * be notified and hasn't given backing store
1053 *result
= T1394_EINVALID_PARAM
;
1055 TNF_PROBE_1(t1394_alloc_addr_error
,
1056 S1394_TNF_SL_ARREQ_ERROR
, "", tnf_string
, msg
,
1058 "(LKs on, notify off, no backing store)");
1059 TNF_PROBE_0_DEBUG(t1394_alloc_addr_exit
,
1060 S1394_TNF_SL_ARREQ_STACK
, "");
1062 /* kstats - addr alloc failures */
1063 hal
->hal_kstats
->addr_alloc_fail
++;
1064 return (DDI_FAILURE
);
1066 addr_allocp
->aa_enable
&= ~T1394_ADDR_LKENBL
;
1070 /* If not T1394_ADDR_FIXED, then allocate a block */
1071 if (addr_allocp
->aa_type
!= T1394_ADDR_FIXED
) {
1072 err
= s1394_request_addr_blk((s1394_hal_t
*)target
->on_hal
,
1074 if (err
!= DDI_SUCCESS
) {
1075 *result
= T1394_EALLOC_ADDR
;
1076 /* kstats - addr alloc failures */
1077 hal
->hal_kstats
->addr_alloc_fail
++;
1079 *result
= T1394_NOERROR
;
1081 TNF_PROBE_0_DEBUG(t1394_alloc_addr_exit
,
1082 S1394_TNF_SL_ARREQ_STACK
, "");
1085 err
= s1394_claim_addr_blk((s1394_hal_t
*)target
->on_hal
,
1087 if (err
!= DDI_SUCCESS
) {
1088 *result
= T1394_EALLOC_ADDR
;
1089 /* kstats - addr alloc failures */
1090 hal
->hal_kstats
->addr_alloc_fail
++;
1092 *result
= T1394_NOERROR
;
1093 /* If physical, update the AR request counter */
1094 if ((addr_lo
>= hal
->physical_addr_lo
) &&
1095 (addr_hi
<= hal
->physical_addr_hi
)) {
1096 rw_enter(&hal
->target_list_rwlock
, RW_WRITER
);
1097 target
->physical_arreq_enabled
++;
1098 rw_exit(&hal
->target_list_rwlock
);
1100 s1394_physical_arreq_set_one(target
);
1103 TNF_PROBE_0_DEBUG(t1394_alloc_addr_exit
,
1104 S1394_TNF_SL_ARREQ_STACK
, "");
1110 * Function: t1394_free_addr()
1111 * Input(s): t1394_hdl The target "handle" returned by
1113 * addr_hdl The address "handle" returned by the
1114 * the t1394_alloc_addr() routine
1115 * flags The flags parameter is unused (for now)
1117 * Output(s): DDI_SUCCESS Target successfully freed memory
1118 * DDI_FAILURE Target failed to free the memory block
1120 * Description: t1394_free_addr() attempts to free up memory that has been
1121 * allocated by the target using t1394_alloc_addr().
1125 t1394_free_addr(t1394_handle_t t1394_hdl
, t1394_addr_handle_t
*addr_hdl
,
1128 s1394_addr_space_blk_t
*curr_blk
;
1130 s1394_target_t
*target
;
1132 TNF_PROBE_0_DEBUG(t1394_free_addr_enter
, S1394_TNF_SL_ARREQ_STACK
, "");
1134 ASSERT(t1394_hdl
!= NULL
);
1135 ASSERT(addr_hdl
!= NULL
);
1137 target
= (s1394_target_t
*)t1394_hdl
;
1139 /* Find the HAL this target resides on */
1140 hal
= target
->on_hal
;
1142 curr_blk
= (s1394_addr_space_blk_t
*)(*addr_hdl
);
1144 if (s1394_free_addr_blk(hal
, curr_blk
) != DDI_SUCCESS
) {
1145 TNF_PROBE_0_DEBUG(t1394_free_addr_exit
,
1146 S1394_TNF_SL_ARREQ_STACK
, "");
1147 return (DDI_FAILURE
);
1150 /* If physical, update the AR request counter */
1151 if (curr_blk
->addr_type
== T1394_ADDR_FIXED
) {
1152 target
->physical_arreq_enabled
--;
1153 s1394_physical_arreq_clear_one(target
);
1158 /* kstats - number of addr frees */
1159 hal
->hal_kstats
->addr_space_free
++;
1161 TNF_PROBE_0_DEBUG(t1394_free_addr_exit
, S1394_TNF_SL_ARREQ_STACK
, "");
1162 return (DDI_SUCCESS
);
1166 * Function: t1394_recv_request_done()
1167 * Input(s): t1394_hdl The target "handle" returned by
1169 * resp Pointer to the command which the
1170 * target received in it's callback
1171 * flags The flags parameter is unused (for now)
1173 * Output(s): DDI_SUCCESS Target successfully returned command
1174 * to the 1394 Software Framework,
1175 * and, if necessary, sent response
1176 * DDI_FAILURE Target failed to return the command to
1177 * the 1394 Software Framework
1179 * Description: t1394_recv_request_done() takes the command that is given and
1180 * determines whether that command requires a response to be
1181 * sent on the 1394 bus. If it is necessary and it's response
1182 * code (cmd_result) has been set appropriately, then a response
1183 * will be sent. If no response is necessary (broadcast or
1184 * posted write), then the command resources are reclaimed.
1188 t1394_recv_request_done(t1394_handle_t t1394_hdl
, cmd1394_cmd_t
*resp
,
1192 s1394_cmd_priv_t
*s_priv
;
1193 h1394_cmd_priv_t
*h_priv
;
1198 boolean_t response
= B_TRUE
;
1199 boolean_t posted_write
= B_FALSE
;
1200 boolean_t write_cmd
= B_FALSE
;
1201 boolean_t mblk_too_small
;
1203 TNF_PROBE_0_DEBUG(t1394_recv_request_done_enter
,
1204 S1394_TNF_SL_ARREQ_STACK
, "");
1206 ASSERT(t1394_hdl
!= NULL
);
1207 ASSERT(resp
!= NULL
);
1209 /* Find the HAL this target resides on */
1210 hal
= ((s1394_target_t
*)t1394_hdl
)->on_hal
;
1212 /* Get the Services Layer private area */
1213 s_priv
= S1394_GET_CMD_PRIV(resp
);
1215 /* Get a pointer to the HAL private struct */
1216 h_priv
= (h1394_cmd_priv_t
*)&s_priv
->hal_cmd_private
;
1218 /* Is this an FA request? */
1219 if (s_priv
->cmd_ext_type
== S1394_CMD_EXT_FA
) {
1220 s1394_fa_convert_cmd(hal
, resp
);
1223 /* Is this a write request? */
1224 if ((resp
->cmd_type
== CMD1394_ASYNCH_WR_QUAD
) ||
1225 (resp
->cmd_type
== CMD1394_ASYNCH_WR_BLOCK
)) {
1227 /* Is this a posted write request? */
1228 posted_write
= s_priv
->posted_write
;
1231 /* If broadcast or posted write cmd, don't send response */
1232 if ((resp
->broadcast
== 1) ||
1233 ((write_cmd
== B_TRUE
) && (posted_write
== B_TRUE
)))
1236 if (response
== B_FALSE
) {
1237 if ((write_cmd
== B_TRUE
) && (posted_write
== B_TRUE
)) {
1238 /* kstats - Posted Write error */
1239 hal
->hal_kstats
->arreq_posted_write_error
++;
1242 /* Free the command - Pass it back to the HAL */
1243 HAL_CALL(hal
).response_complete(hal
->halinfo
.hal_private
, resp
,
1245 TNF_PROBE_0_DEBUG(t1394_recv_request_done_exit
,
1246 S1394_TNF_SL_ARREQ_STACK
, "");
1247 return (DDI_SUCCESS
);
1250 ASSERT(response
== B_TRUE
);
1252 /* Verify valid response code */
1253 switch (resp
->cmd_result
) {
1254 case IEEE1394_RESP_COMPLETE
:
1255 /* Is the mblk_t too small? */
1256 if (resp
->cmd_type
== CMD1394_ASYNCH_RD_BLOCK
) {
1257 curr_blk
= resp
->cmd_u
.b
.data_block
;
1258 size
= resp
->cmd_u
.b
.blk_length
;
1260 mblk_too_small
= B_TRUE
;
1262 if (curr_blk
== NULL
) {
1263 TNF_PROBE_1(t1394_recv_request_done_error
,
1264 S1394_TNF_SL_ARREQ_ERROR
, "", tnf_string
,
1265 msg
, "mblk_t is NULL in response");
1266 TNF_PROBE_0_DEBUG(t1394_recv_request_done_exit
,
1267 S1394_TNF_SL_ARREQ_STACK
, "");
1269 * Free the command - Pass it back
1272 HAL_CALL(hal
).response_complete(
1273 hal
->halinfo
.hal_private
, resp
, h_priv
);
1274 ASSERT(curr_blk
!= NULL
);
1275 return (DDI_FAILURE
);
1278 while (curr_blk
!= NULL
) {
1280 (curr_blk
->b_wptr
- curr_blk
->b_rptr
);
1282 if (msgb_len
>= size
) {
1283 mblk_too_small
= B_FALSE
;
1286 curr_blk
= curr_blk
->b_cont
;
1289 if (mblk_too_small
== B_TRUE
) {
1290 TNF_PROBE_1(t1394_recv_request_done_error
,
1291 S1394_TNF_SL_ARREQ_ERROR
, "", tnf_string
,
1292 msg
, "mblk_t too small in response");
1293 TNF_PROBE_0_DEBUG(t1394_recv_request_done_exit
,
1294 S1394_TNF_SL_ARREQ_STACK
, "");
1296 * Free the command - Pass it back
1299 HAL_CALL(hal
).response_complete(
1300 hal
->halinfo
.hal_private
, resp
, h_priv
);
1301 ASSERT(mblk_too_small
!= B_TRUE
);
1302 return (DDI_FAILURE
);
1306 case IEEE1394_RESP_CONFLICT_ERROR
:
1307 case IEEE1394_RESP_DATA_ERROR
:
1308 case IEEE1394_RESP_TYPE_ERROR
:
1309 case IEEE1394_RESP_ADDRESS_ERROR
:
1310 ret
= s1394_send_response(hal
, resp
);
1311 TNF_PROBE_0_DEBUG(t1394_recv_request_done_exit
,
1312 S1394_TNF_SL_ARREQ_STACK
, "");
1316 TNF_PROBE_1(t1394_recv_request_done_error
,
1317 S1394_TNF_SL_ARREQ_ERROR
, "", tnf_string
, msg
,
1318 "Invalid response code");
1319 TNF_PROBE_0_DEBUG(t1394_recv_request_done_exit
,
1320 S1394_TNF_SL_ARREQ_STACK
, "");
1321 return (DDI_FAILURE
);
1327 * Function: t1394_fcp_register_controller()
1328 * Input(s): t1394_hdl The target "handle" returned by
1330 * evts The structure in which the target
1331 * specifies its callback routines
1333 * flags The flags parameter is unused (for now)
1335 * Output(s): DDI_SUCCESS Successfully registered.
1337 * DDI_FAILURE Not registered due to failure.
1339 * Description: Used to register the target within the Framework as an FCP
1344 t1394_fcp_register_controller(t1394_handle_t t1394_hdl
, t1394_fcp_evts_t
*evts
,
1349 TNF_PROBE_0_DEBUG(t1394_fcp_register_controller_enter
,
1350 S1394_TNF_SL_FCP_STACK
, "");
1352 ASSERT(t1394_hdl
!= NULL
);
1354 result
= s1394_fcp_register_ctl((s1394_target_t
*)t1394_hdl
, evts
);
1356 TNF_PROBE_0_DEBUG(t1394_fcp_register_controller_exit
,
1357 S1394_TNF_SL_FCP_STACK
, "");
1362 * Function: t1394_fcp_unregister_controller()
1363 * Input(s): t1394_hdl The target "handle" returned by
1366 * Output(s): DDI_SUCCESS Successfully unregistered.
1368 * DDI_FAILURE Not unregistered due to failure.
1370 * Description: Used to unregister the target within the Framework as an FCP
1374 t1394_fcp_unregister_controller(t1394_handle_t t1394_hdl
)
1378 TNF_PROBE_0_DEBUG(t1394_fcp_unregister_controller_enter
,
1379 S1394_TNF_SL_FCP_STACK
, "");
1381 ASSERT(t1394_hdl
!= NULL
);
1383 result
= s1394_fcp_unregister_ctl((s1394_target_t
*)t1394_hdl
);
1385 TNF_PROBE_0_DEBUG(t1394_fcp_unregister_controller_exit
,
1386 S1394_TNF_SL_FCP_STACK
, "");
1391 * Function: t1394_fcp_register_target()
1392 * Input(s): t1394_hdl The target "handle" returned by
1394 * evts The structure in which the target
1395 * specifies its callback routines
1397 * flags The flags parameter is unused (for now)
1399 * Output(s): DDI_SUCCESS Successfully registered.
1401 * DDI_FAILURE Not registered due to failure.
1403 * Description: Used to register the target within the Framework as an FCP
1408 t1394_fcp_register_target(t1394_handle_t t1394_hdl
, t1394_fcp_evts_t
*evts
,
1413 TNF_PROBE_0_DEBUG(t1394_fcp_register_target_enter
,
1414 S1394_TNF_SL_FCP_STACK
, "");
1416 ASSERT(t1394_hdl
!= NULL
);
1418 result
= s1394_fcp_register_tgt((s1394_target_t
*)t1394_hdl
, evts
);
1420 TNF_PROBE_0_DEBUG(t1394_fcp_register_target_exit
,
1421 S1394_TNF_SL_FCP_STACK
, "");
1426 * Function: t1394_fcp_unregister_target()
1427 * Input(s): t1394_hdl The target "handle" returned by
1430 * Output(s): DDI_SUCCESS Successfully unregistered.
1432 * DDI_FAILURE Not unregistered due to failure.
1434 * Description: Used to unregister the target within the Framework as an FCP
1438 t1394_fcp_unregister_target(t1394_handle_t t1394_hdl
)
1442 TNF_PROBE_0_DEBUG(t1394_fcp_unregister_target_enter
,
1443 S1394_TNF_SL_FCP_STACK
, "");
1445 ASSERT(t1394_hdl
!= NULL
);
1447 result
= s1394_fcp_unregister_tgt((s1394_target_t
*)t1394_hdl
);
1449 TNF_PROBE_0_DEBUG(t1394_fcp_unregister_target_exit
,
1450 S1394_TNF_SL_FCP_STACK
, "");
1455 * Function: t1394_cmp_register()
1456 * Input(s): t1394_hdl The target "handle" returned by
1458 * evts The structure in which the target
1459 * specifies its callback routines
1461 * Output(s): DDI_SUCCESS Successfully registered.
1463 * DDI_FAILURE Not registered due to failure.
1465 * Description: Used to register the target within the Framework as a CMP
1470 t1394_cmp_register(t1394_handle_t t1394_hdl
, t1394_cmp_evts_t
*evts
,
1475 TNF_PROBE_0_DEBUG(t1394_cmp_register_enter
, S1394_TNF_SL_CMP_STACK
, "");
1477 ASSERT(t1394_hdl
!= NULL
);
1479 result
= s1394_cmp_register((s1394_target_t
*)t1394_hdl
, evts
);
1481 TNF_PROBE_0_DEBUG(t1394_cmp_register_exit
, S1394_TNF_SL_CMP_STACK
, "");
1486 * Function: t1394_cmp_unregister()
1487 * Input(s): t1394_hdl The target "handle" returned by
1489 * evts The structure in which the target
1490 * specifies its callback routines
1492 * Output(s): DDI_SUCCESS Successfully registered.
1494 * DDI_FAILURE Not registered due to failure.
1496 * Description: Used to unregister the target within the Framework as a CMP
1500 t1394_cmp_unregister(t1394_handle_t t1394_hdl
)
1504 TNF_PROBE_0_DEBUG(t1394_cmp_unregister_enter
, S1394_TNF_SL_CMP_STACK
,
1507 ASSERT(t1394_hdl
!= NULL
);
1509 result
= s1394_cmp_unregister((s1394_target_t
*)t1394_hdl
);
1511 TNF_PROBE_0_DEBUG(t1394_cmp_unregister_exit
, S1394_TNF_SL_CMP_STACK
,
1517 * Function: t1394_cmp_read()
1518 * Input(s): t1394_hdl The target "handle" returned by
1520 * reg Register type.
1521 * valp Returned register value.
1523 * Output(s): DDI_SUCCESS Successfully registered.
1525 * DDI_FAILURE Not registered due to failure.
1527 * Description: Used to read a CMP register value.
1530 t1394_cmp_read(t1394_handle_t t1394_hdl
, t1394_cmp_reg_t reg
, uint32_t *valp
)
1534 TNF_PROBE_0_DEBUG(t1394_cmp_read_enter
, S1394_TNF_SL_CMP_STACK
, "");
1536 ASSERT(t1394_hdl
!= NULL
);
1538 result
= s1394_cmp_read((s1394_target_t
*)t1394_hdl
, reg
, valp
);
1540 TNF_PROBE_0_DEBUG(t1394_cmp_read_exit
, S1394_TNF_SL_CMP_STACK
, "");
1545 * Function: t1394_cmp_cas()
1546 * Input(s): t1394_hdl The target "handle" returned by
1548 * reg Register type.
1549 * arg_val Compare argument.
1550 * new_val New register value.
1551 * old_valp Returned original register value.
1553 * Output(s): DDI_SUCCESS Successfully registered.
1555 * DDI_FAILURE Not registered due to failure.
1557 * Description: Used to compare-swap a CMP register value.
1560 t1394_cmp_cas(t1394_handle_t t1394_hdl
, t1394_cmp_reg_t reg
, uint32_t arg_val
,
1561 uint32_t new_val
, uint32_t *old_valp
)
1565 TNF_PROBE_0_DEBUG(t1394_cmp_read_enter
, S1394_TNF_SL_CMP_STACK
, "");
1567 ASSERT(t1394_hdl
!= NULL
);
1569 result
= s1394_cmp_cas((s1394_target_t
*)t1394_hdl
, reg
, arg_val
,
1572 TNF_PROBE_0_DEBUG(t1394_cmp_read_exit
, S1394_TNF_SL_CMP_STACK
, "");
1577 * Function: t1394_alloc_isoch_single()
1578 * Input(s): t1394_hdl The target "handle" returned by
1580 * sii The structure used to set up the
1581 * overall characteristics of the
1582 * isochronous stream
1583 * flags The flags parameter is unused (for now)
1585 * Output(s): setup_args Contains the channel number that was
1587 * t1394_single_hdl This in the isoch "handle" used in
1588 * t1394_free_isoch_single()
1589 * result Used to pass more specific info back
1592 * Description: t1394_alloc_isoch_single() is used to direct the 1394 Software
1593 * Framework to allocate an isochronous channel and bandwidth
1594 * from the Isochronous Resource Manager (IRM). If a bus reset
1595 * occurs, the 1394 Software Framework attempts to reallocate the
1596 * same resources, calling the rsrc_fail_target() callback if
1597 * it is unsuccessful.
1601 t1394_alloc_isoch_single(t1394_handle_t t1394_hdl
,
1602 t1394_isoch_singleinfo_t
*sii
, uint_t flags
,
1603 t1394_isoch_single_out_t
*output_args
,
1604 t1394_isoch_single_handle_t
*t1394_single_hdl
, int *result
)
1607 s1394_isoch_cec_t
*cec_new
;
1608 t1394_join_isochinfo_t jii
;
1612 TNF_PROBE_0_DEBUG(t1394_alloc_isoch_single_enter
,
1613 S1394_TNF_SL_ISOCH_STACK
, "");
1615 ASSERT(t1394_hdl
!= NULL
);
1616 ASSERT(t1394_single_hdl
!= NULL
);
1617 ASSERT(sii
!= NULL
);
1619 hal
= ((s1394_target_t
*)t1394_hdl
)->on_hal
;
1621 /* Check for invalid channel_mask */
1622 if (sii
->si_channel_mask
== 0) {
1623 TNF_PROBE_1(t1394_alloc_isoch_single_error
,
1624 S1394_TNF_SL_ISOCH_ERROR
, "", tnf_string
, msg
,
1625 "Invalid channel mask");
1626 TNF_PROBE_0_DEBUG(t1394_alloc_isoch_single_exit
,
1627 S1394_TNF_SL_ISOCH_STACK
, "");
1628 return (DDI_FAILURE
);
1631 /* Check for invalid bandwidth */
1632 if ((sii
->si_bandwidth
<= IEEE1394_BANDWIDTH_MIN
) ||
1633 (sii
->si_bandwidth
> IEEE1394_BANDWIDTH_MAX
)) {
1634 TNF_PROBE_1(t1394_alloc_isoch_single_error
,
1635 S1394_TNF_SL_ISOCH_ERROR
, "", tnf_string
, msg
,
1636 "Invalid bandwidth requirements");
1637 TNF_PROBE_0_DEBUG(t1394_alloc_isoch_single_exit
,
1638 S1394_TNF_SL_ISOCH_STACK
, "");
1639 return (DDI_FAILURE
);
1642 /* Verify that rsrc_fail_target() callback is non-NULL */
1643 if (sii
->rsrc_fail_target
== NULL
) {
1644 TNF_PROBE_1(t1394_alloc_isoch_single_error
,
1645 S1394_TNF_SL_ISOCH_ERROR
, "", tnf_string
, msg
,
1646 "Invalid callback specified");
1647 TNF_PROBE_0_DEBUG(t1394_alloc_isoch_single_exit
,
1648 S1394_TNF_SL_ISOCH_STACK
, "");
1649 return (DDI_FAILURE
);
1653 * Allocate an Isoch CEC of type S1394_SINGLE
1656 /* Allocate the Isoch CEC structure */
1657 cec_new
= kmem_zalloc(sizeof (s1394_isoch_cec_t
), KM_SLEEP
);
1659 /* Initialize the structure type */
1660 cec_new
->cec_type
= S1394_SINGLE
;
1662 /* Create the mutex and "in_callbacks" cv */
1663 mutex_init(&cec_new
->isoch_cec_mutex
, NULL
, MUTEX_DRIVER
,
1664 hal
->halinfo
.hw_interrupt
);
1665 cv_init(&cec_new
->in_callbacks_cv
, NULL
, CV_DRIVER
,
1666 hal
->halinfo
.hw_interrupt
);
1668 /* Initialize the Isoch CEC's member list */
1669 cec_new
->cec_member_list_head
= NULL
;
1670 cec_new
->cec_member_list_tail
= NULL
;
1672 /* Initialize the filters */
1673 cec_new
->filter_min_speed
= sii
->si_speed
;
1674 cec_new
->filter_max_speed
= sii
->si_speed
;
1675 cec_new
->filter_current_speed
= cec_new
->filter_max_speed
;
1676 cec_new
->filter_channel_mask
= sii
->si_channel_mask
;
1677 cec_new
->bandwidth
= sii
->si_bandwidth
;
1678 cec_new
->state_transitions
= ISOCH_CEC_FREE
| ISOCH_CEC_JOIN
|
1681 mutex_enter(&hal
->isoch_cec_list_mutex
);
1683 /* Insert Isoch CEC into the HAL's list */
1684 s1394_isoch_cec_list_insert(hal
, cec_new
);
1686 mutex_exit(&hal
->isoch_cec_list_mutex
);
1689 * Join the newly created Isoch CEC
1691 jii
.req_channel_mask
= sii
->si_channel_mask
;
1692 jii
.req_max_speed
= sii
->si_speed
;
1693 jii
.jii_options
= T1394_TALKER
;
1694 jii
.isoch_cec_evts_arg
= sii
->single_evt_arg
;
1696 /* All events are NULL except rsrc_fail_target() */
1697 jii
.isoch_cec_evts
.setup_target
= NULL
;
1698 jii
.isoch_cec_evts
.start_target
= NULL
;
1699 jii
.isoch_cec_evts
.stop_target
= NULL
;
1700 jii
.isoch_cec_evts
.stop_target
= NULL
;
1701 jii
.isoch_cec_evts
.teardown_target
= NULL
;
1702 jii
.isoch_cec_evts
.rsrc_fail_target
= sii
->rsrc_fail_target
;
1704 ret
= t1394_join_isoch_cec(t1394_hdl
,
1705 (t1394_isoch_cec_handle_t
)cec_new
, 0, &jii
);
1707 if (ret
!= DDI_SUCCESS
) {
1708 TNF_PROBE_1(t1394_alloc_isoch_single_error
,
1709 S1394_TNF_SL_ISOCH_ERROR
, "", tnf_string
, msg
,
1710 "Unexpected error from t1394_join_isoch_cec()");
1712 ret
= t1394_free_isoch_cec(t1394_hdl
, flags
,
1713 (t1394_isoch_cec_handle_t
*)&cec_new
);
1714 if (ret
!= DDI_SUCCESS
) {
1715 /* Unable to free the Isoch CEC */
1716 TNF_PROBE_1(t1394_alloc_isoch_single_error
,
1717 S1394_TNF_SL_ISOCH_ERROR
, "", tnf_string
, msg
,
1718 "Unexpected error from t1394_free_isoch_cec()");
1722 /* Handle is nulled out before returning */
1723 *t1394_single_hdl
= NULL
;
1725 TNF_PROBE_0_DEBUG(t1394_alloc_isoch_single_exit
,
1726 S1394_TNF_SL_ISOCH_STACK
, "");
1727 return (DDI_FAILURE
);
1731 * Setup the isoch resources, etc.
1733 ret
= t1394_setup_isoch_cec(t1394_hdl
,
1734 (t1394_isoch_cec_handle_t
)cec_new
, 0, &err
);
1736 if (ret
!= DDI_SUCCESS
) {
1737 TNF_PROBE_1(t1394_alloc_isoch_single_error
,
1738 S1394_TNF_SL_ISOCH_ERROR
, "", tnf_string
, msg
,
1739 "Unexpected error from t1394_setup_isoch_cec()");
1743 /* Leave the Isoch CEC */
1744 ret
= t1394_leave_isoch_cec(t1394_hdl
,
1745 (t1394_isoch_cec_handle_t
)cec_new
, 0);
1746 if (ret
!= DDI_SUCCESS
) {
1747 /* Unable to leave the Isoch CEC */
1748 TNF_PROBE_1(t1394_alloc_isoch_single_error
,
1749 S1394_TNF_SL_ISOCH_ERROR
, "", tnf_string
, msg
,
1750 "Unexpected error from t1394_leave_isoch_cec()");
1754 /* Free up the Isoch CEC */
1755 ret
= t1394_free_isoch_cec(t1394_hdl
, flags
,
1756 (t1394_isoch_cec_handle_t
*)&cec_new
);
1757 if (ret
!= DDI_SUCCESS
) {
1758 /* Unable to free the Isoch CEC */
1759 TNF_PROBE_1(t1394_alloc_isoch_single_error
,
1760 S1394_TNF_SL_ISOCH_ERROR
, "", tnf_string
, msg
,
1761 "Unexpected error from t1394_free_isoch_cec()");
1765 /* Handle is nulled out before returning */
1766 *t1394_single_hdl
= NULL
;
1768 TNF_PROBE_0_DEBUG(t1394_alloc_isoch_single_exit
,
1769 S1394_TNF_SL_ISOCH_STACK
, "");
1770 return (DDI_FAILURE
);
1773 /* Return the setup_args - channel num and speed */
1774 mutex_enter(&cec_new
->isoch_cec_mutex
);
1775 output_args
->channel_num
= cec_new
->realloc_chnl_num
;
1776 mutex_exit(&cec_new
->isoch_cec_mutex
);
1778 /* Update the handle */
1779 *t1394_single_hdl
= (t1394_isoch_single_handle_t
)cec_new
;
1781 TNF_PROBE_0_DEBUG(t1394_alloc_isoch_single_exit
,
1782 S1394_TNF_SL_ISOCH_STACK
, "");
1783 return (DDI_SUCCESS
);
1787 * Function: t1394_free_isoch_single()
1788 * Input(s): t1394_hdl The target "handle" returned by
1790 * t1394_single_hdl The isoch "handle" return by
1791 * t1394_alloc_isoch_single()
1792 * flags The flags parameter is unused (for now)
1796 * Description: t1394_free_isoch_single() frees the isochronous resources
1797 * and the handle that were allocated during the call to
1798 * t1394_alloc_isoch_single().
1802 t1394_free_isoch_single(t1394_handle_t t1394_hdl
,
1803 t1394_isoch_single_handle_t
*t1394_single_hdl
, uint_t flags
)
1805 s1394_isoch_cec_t
*cec_curr
;
1808 TNF_PROBE_0_DEBUG(t1394_free_isoch_single_enter
,
1809 S1394_TNF_SL_ISOCH_STACK
, "");
1811 ASSERT(t1394_hdl
!= NULL
);
1812 ASSERT(t1394_single_hdl
!= NULL
);
1814 /* Convert the handle to an Isoch CEC pointer */
1815 cec_curr
= (s1394_isoch_cec_t
*)(*t1394_single_hdl
);
1818 * Teardown the isoch resources, etc.
1820 ret
= t1394_teardown_isoch_cec(t1394_hdl
,
1821 (t1394_isoch_cec_handle_t
)cec_curr
, 0);
1822 if (ret
!= DDI_SUCCESS
) {
1823 /* Unable to teardown the Isoch CEC */
1824 TNF_PROBE_1(t1394_free_isoch_single_error
,
1825 S1394_TNF_SL_ISOCH_ERROR
, "", tnf_string
, msg
,
1826 "Unexpected error from t1394_teardown_isoch_cec()");
1831 * Leave the Isoch CEC
1833 ret
= t1394_leave_isoch_cec(t1394_hdl
,
1834 (t1394_isoch_cec_handle_t
)cec_curr
, 0);
1835 if (ret
!= DDI_SUCCESS
) {
1836 /* Unable to leave the Isoch CEC */
1837 TNF_PROBE_1(t1394_free_isoch_single_error
,
1838 S1394_TNF_SL_ISOCH_ERROR
, "", tnf_string
, msg
,
1839 "Unexpected error from t1394_leave_isoch_cec()");
1844 * Free the Isoch CEC
1846 ret
= t1394_free_isoch_cec(t1394_hdl
, flags
,
1847 (t1394_isoch_cec_handle_t
*)&cec_curr
);
1848 if (ret
!= DDI_SUCCESS
) {
1849 /* Unable to free the Isoch CEC */
1850 TNF_PROBE_1(t1394_free_isoch_single_error
,
1851 S1394_TNF_SL_ISOCH_ERROR
, "", tnf_string
, msg
,
1852 "Unexpected error from t1394_free_isoch_cec()");
1856 /* Handle is nulled out before returning */
1857 *t1394_single_hdl
= NULL
;
1859 TNF_PROBE_0_DEBUG(t1394_free_isoch_single_exit
,
1860 S1394_TNF_SL_ISOCH_STACK
, "");
1864 * Function: t1394_alloc_isoch_cec()
1865 * Input(s): t1394_hdl The target "handle" returned by
1867 * props The structure used to set up the
1868 * overall characteristics of for
1870 * flags The flags parameter is unused (for now)
1872 * Output(s): t1394_isoch_cec_hdl The Isoch CEC "handle" used in all
1873 * subsequent isoch_cec() calls
1875 * Description: t1394_alloc_isoch_cec() allocates and initializes an
1876 * isochronous channel event coordinator (Isoch CEC) for use
1877 * in managing and coordinating activity for an isoch channel
1881 t1394_alloc_isoch_cec(t1394_handle_t t1394_hdl
, t1394_isoch_cec_props_t
*props
,
1882 uint_t flags
, t1394_isoch_cec_handle_t
*t1394_isoch_cec_hdl
)
1885 s1394_isoch_cec_t
*cec_new
;
1888 TNF_PROBE_0_DEBUG(t1394_alloc_isoch_cec_enter
,
1889 S1394_TNF_SL_ISOCH_STACK
, "");
1891 ASSERT(t1394_hdl
!= NULL
);
1892 ASSERT(t1394_isoch_cec_hdl
!= NULL
);
1893 ASSERT(props
!= NULL
);
1895 hal
= ((s1394_target_t
*)t1394_hdl
)->on_hal
;
1897 /* Check for invalid channel_mask */
1898 if (props
->cec_channel_mask
== 0) {
1899 TNF_PROBE_1(t1394_alloc_isoch_cec_error
,
1900 S1394_TNF_SL_ISOCH_ERROR
, "", tnf_string
, msg
,
1901 "Invalid channel mask");
1902 TNF_PROBE_0_DEBUG(t1394_alloc_isoch_cec_exit
,
1903 S1394_TNF_SL_ISOCH_STACK
, "");
1904 return (DDI_FAILURE
);
1907 /* Test conditions specific to T1394_NO_IRM_ALLOC */
1908 temp
= props
->cec_channel_mask
;
1909 if (props
->cec_options
& T1394_NO_IRM_ALLOC
) {
1910 /* If T1394_NO_IRM_ALLOC, then only one bit should be set */
1912 TNF_PROBE_1(t1394_alloc_isoch_cec_error
,
1913 S1394_TNF_SL_ISOCH_ERROR
, "", tnf_string
, msg
,
1914 "Invalid channel mask");
1915 TNF_PROBE_0_DEBUG(t1394_alloc_isoch_cec_exit
,
1916 S1394_TNF_SL_ISOCH_STACK
, "");
1917 return (DDI_FAILURE
);
1920 /* If T1394_NO_IRM_ALLOC, then speeds should be equal */
1921 if (props
->cec_min_speed
!= props
->cec_max_speed
) {
1922 TNF_PROBE_1(t1394_alloc_isoch_cec_error
,
1923 S1394_TNF_SL_ISOCH_ERROR
, "", tnf_string
, msg
,
1924 "Invalid speeds (min != max)");
1925 TNF_PROBE_0_DEBUG(t1394_alloc_isoch_cec_exit
,
1926 S1394_TNF_SL_ISOCH_STACK
, "");
1927 return (DDI_FAILURE
);
1931 /* Check for invalid bandwidth */
1932 if ((props
->cec_bandwidth
<= IEEE1394_BANDWIDTH_MIN
) ||
1933 (props
->cec_bandwidth
> IEEE1394_BANDWIDTH_MAX
)) {
1934 TNF_PROBE_1(t1394_alloc_isoch_cec_error
,
1935 S1394_TNF_SL_ISOCH_ERROR
, "", tnf_string
, msg
,
1936 "Invalid bandwidth requirements");
1937 TNF_PROBE_0_DEBUG(t1394_alloc_isoch_cec_exit
,
1938 S1394_TNF_SL_ISOCH_STACK
, "");
1939 return (DDI_FAILURE
);
1942 /* Allocate the Isoch CEC structure */
1943 cec_new
= kmem_zalloc(sizeof (s1394_isoch_cec_t
), KM_SLEEP
);
1945 /* Initialize the structure type */
1946 cec_new
->cec_type
= S1394_PEER_TO_PEER
;
1948 /* Create the mutex and "in_callbacks" cv */
1949 mutex_init(&cec_new
->isoch_cec_mutex
, NULL
, MUTEX_DRIVER
,
1950 hal
->halinfo
.hw_interrupt
);
1951 cv_init(&cec_new
->in_callbacks_cv
, NULL
, CV_DRIVER
,
1952 hal
->halinfo
.hw_interrupt
);
1954 /* Initialize the Isoch CEC's member list */
1955 cec_new
->cec_member_list_head
= NULL
;
1956 cec_new
->cec_member_list_tail
= NULL
;
1958 /* Initialize the filters */
1959 cec_new
->filter_min_speed
= props
->cec_min_speed
;
1960 cec_new
->filter_max_speed
= props
->cec_max_speed
;
1961 cec_new
->filter_current_speed
= cec_new
->filter_max_speed
;
1962 cec_new
->filter_channel_mask
= props
->cec_channel_mask
;
1963 cec_new
->bandwidth
= props
->cec_bandwidth
;
1964 cec_new
->cec_options
= props
->cec_options
;
1965 cec_new
->state_transitions
= ISOCH_CEC_FREE
| ISOCH_CEC_JOIN
|
1968 mutex_enter(&hal
->isoch_cec_list_mutex
);
1970 /* Insert Isoch CEC into the HAL's list */
1971 s1394_isoch_cec_list_insert(hal
, cec_new
);
1973 mutex_exit(&hal
->isoch_cec_list_mutex
);
1975 /* Update the handle and return */
1976 *t1394_isoch_cec_hdl
= (t1394_isoch_cec_handle_t
)cec_new
;
1978 TNF_PROBE_0_DEBUG(t1394_alloc_isoch_cec_exit
,
1979 S1394_TNF_SL_ISOCH_STACK
, "");
1980 return (DDI_SUCCESS
);
1984 * Function: t1394_free_isoch_cec()
1985 * Input(s): t1394_hdl The target "handle" returned by
1987 * flags The flags parameter is unused (for now)
1988 * t1394_isoch_cec_hdl The Isoch CEC "handle" returned by
1989 * t1394_alloc_isoch_cec()
1991 * Output(s): DDI_SUCCESS Target successfully freed the Isoch CEC
1992 * DDI_FAILURE Target failed to free the Isoch CEC
1994 * Description: t1394_free_isoch_cec() attempts to free the Isoch CEC
1995 * structure. It will fail (DDI_FAILURE) if there are any
1996 * remaining members who have not yet left.
2000 t1394_free_isoch_cec(t1394_handle_t t1394_hdl
, uint_t flags
,
2001 t1394_isoch_cec_handle_t
*t1394_isoch_cec_hdl
)
2004 s1394_isoch_cec_t
*cec_curr
;
2006 TNF_PROBE_0_DEBUG(t1394_free_isoch_cec_enter
,
2007 S1394_TNF_SL_ISOCH_STACK
, "");
2009 ASSERT(t1394_hdl
!= NULL
);
2010 ASSERT(t1394_isoch_cec_hdl
!= NULL
);
2012 hal
= ((s1394_target_t
*)t1394_hdl
)->on_hal
;
2014 /* Convert the handle to an Isoch CEC pointer */
2015 cec_curr
= (s1394_isoch_cec_t
*)(*t1394_isoch_cec_hdl
);
2017 /* Lock the Isoch CEC member list */
2018 mutex_enter(&cec_curr
->isoch_cec_mutex
);
2020 /* Are we in any callbacks? */
2021 if (CEC_IN_ANY_CALLBACKS(cec_curr
)) {
2022 /* Unlock the Isoch CEC member list */
2023 mutex_exit(&cec_curr
->isoch_cec_mutex
);
2024 TNF_PROBE_1(t1394_free_isoch_cec_error
,
2025 S1394_TNF_SL_ISOCH_ERROR
, "", tnf_string
, msg
,
2026 "Not allowed to free Isoch CEC (in callbacks)");
2027 TNF_PROBE_0_DEBUG(t1394_free_isoch_cec_exit
,
2028 S1394_TNF_SL_ISOCH_STACK
, "");
2029 return (DDI_FAILURE
);
2032 /* Is "free" a legal state transition? */
2033 if (CEC_TRANSITION_LEGAL(cec_curr
, ISOCH_CEC_FREE
) == 0) {
2034 /* Unlock the Isoch CEC member list */
2035 mutex_exit(&cec_curr
->isoch_cec_mutex
);
2036 TNF_PROBE_1(t1394_free_isoch_cec_error
,
2037 S1394_TNF_SL_ISOCH_ERROR
, "", tnf_string
, msg
,
2038 "Not allowed to free Isoch CEC");
2039 TNF_PROBE_0_DEBUG(t1394_free_isoch_cec_exit
,
2040 S1394_TNF_SL_ISOCH_STACK
, "");
2041 return (DDI_FAILURE
);
2043 mutex_exit(&cec_curr
->isoch_cec_mutex
);
2045 mutex_enter(&hal
->isoch_cec_list_mutex
);
2047 /* Remove Isoch CEC from HAL's list */
2048 s1394_isoch_cec_list_remove(hal
, cec_curr
);
2050 mutex_exit(&hal
->isoch_cec_list_mutex
);
2052 /* Destroy the Isoch CEC's mutex and cv */
2053 cv_destroy(&cec_curr
->in_callbacks_cv
);
2054 mutex_destroy(&cec_curr
->isoch_cec_mutex
);
2056 /* Free up the memory for the Isoch CEC struct */
2057 kmem_free(cec_curr
, sizeof (s1394_isoch_cec_t
));
2059 /* Update the handle and return */
2060 *t1394_isoch_cec_hdl
= NULL
;
2062 TNF_PROBE_0_DEBUG(t1394_free_isoch_cec_exit
,
2063 S1394_TNF_SL_ISOCH_STACK
, "");
2064 return (DDI_SUCCESS
);
2068 * Function: t1394_join_isoch_cec()
2069 * Input(s): t1394_hdl The target "handle" returned by
2071 * t1394_isoch_cec_hdl The Isoch CEC "handle" returned by
2072 * t1394_alloc_isoch_cec()
2073 * flags The flags parameter is unused (for now)
2074 * join_isoch_info This structure provides infomation
2075 * about a target that wishes to join
2076 * the given Isoch CEC. It gives
2077 * max_speed, channel_mask, etc.
2079 * Output(s): DDI_SUCCESS Target successfully joined the
2081 * DDI_FAILURE Target failed to join the Isoch CEC
2083 * Description: t1394_join_isoch_cec() determines, based on the information
2084 * given in the join_isoch_info structure, if the target may
2085 * join the Isoch CEC. If it is determined that the target may
2086 * join, the specified callback routines are stored away for
2087 * later use in the coordination tasks.
2091 t1394_join_isoch_cec(t1394_handle_t t1394_hdl
,
2092 t1394_isoch_cec_handle_t t1394_isoch_cec_hdl
, uint_t flags
,
2093 t1394_join_isochinfo_t
*join_isoch_info
)
2096 s1394_isoch_cec_t
*cec_curr
;
2097 s1394_isoch_cec_member_t
*member_new
;
2098 uint64_t check_mask
;
2099 uint_t curr_max_speed
;
2101 TNF_PROBE_0_DEBUG(t1394_join_isoch_cec_enter
,
2102 S1394_TNF_SL_ISOCH_STACK
, "");
2104 ASSERT(t1394_hdl
!= NULL
);
2105 ASSERT(t1394_isoch_cec_hdl
!= NULL
);
2107 hal
= ((s1394_target_t
*)t1394_hdl
)->on_hal
;
2109 /* Convert the handle to an Isoch CEC pointer */
2110 cec_curr
= (s1394_isoch_cec_t
*)t1394_isoch_cec_hdl
;
2112 /* Allocate a new Isoch CEC member structure */
2113 member_new
= kmem_zalloc(sizeof (s1394_isoch_cec_member_t
), KM_SLEEP
);
2115 /* Lock the Isoch CEC member list */
2116 mutex_enter(&cec_curr
->isoch_cec_mutex
);
2118 /* Are we in any callbacks? (Wait for them to finish) */
2119 while (CEC_IN_ANY_CALLBACKS(cec_curr
)) {
2120 cec_curr
->cec_want_wakeup
= B_TRUE
;
2121 cv_wait(&cec_curr
->in_callbacks_cv
,
2122 &cec_curr
->isoch_cec_mutex
);
2125 /* Is "join" a legal state transition? */
2126 if (CEC_TRANSITION_LEGAL(cec_curr
, ISOCH_CEC_JOIN
) == 0) {
2127 kmem_free(member_new
, sizeof (s1394_isoch_cec_member_t
));
2128 /* Unlock the Isoch CEC member list */
2129 mutex_exit(&cec_curr
->isoch_cec_mutex
);
2130 TNF_PROBE_1(t1394_join_isoch_cec_error
,
2131 S1394_TNF_SL_ISOCH_ERROR
, "", tnf_string
, msg
,
2132 "Not allowed to join Isoch CEC");
2133 TNF_PROBE_0_DEBUG(t1394_join_isoch_cec_exit
,
2134 S1394_TNF_SL_ISOCH_STACK
, "");
2135 return (DDI_FAILURE
);
2138 /* Check the channel mask for consistency */
2139 check_mask
= join_isoch_info
->req_channel_mask
&
2140 cec_curr
->filter_channel_mask
;
2141 if (check_mask
== 0) {
2142 kmem_free(member_new
, sizeof (s1394_isoch_cec_member_t
));
2143 /* Unlock the Isoch CEC member list */
2144 mutex_exit(&cec_curr
->isoch_cec_mutex
);
2145 TNF_PROBE_1(t1394_join_isoch_cec_error
,
2146 S1394_TNF_SL_ISOCH_ERROR
, "", tnf_string
, msg
,
2147 "Inconsistent channel mask specified");
2148 TNF_PROBE_0_DEBUG(t1394_join_isoch_cec_exit
,
2149 S1394_TNF_SL_ISOCH_STACK
, "");
2150 return (DDI_FAILURE
);
2153 /* Check for consistent speeds */
2154 if (join_isoch_info
->req_max_speed
< cec_curr
->filter_min_speed
) {
2155 kmem_free(member_new
, sizeof (s1394_isoch_cec_member_t
));
2156 /* Unlock the Isoch CEC member list */
2157 mutex_exit(&cec_curr
->isoch_cec_mutex
);
2158 TNF_PROBE_1(t1394_join_isoch_cec_error
,
2159 S1394_TNF_SL_ISOCH_ERROR
, "", tnf_string
, msg
,
2160 "Inconsistent speed specified");
2161 TNF_PROBE_0_DEBUG(t1394_join_isoch_cec_exit
,
2162 S1394_TNF_SL_ISOCH_STACK
, "");
2163 return (DDI_FAILURE
);
2164 } else if (join_isoch_info
->req_max_speed
<
2165 cec_curr
->filter_current_speed
) {
2166 curr_max_speed
= join_isoch_info
->req_max_speed
;
2168 curr_max_speed
= cec_curr
->filter_current_speed
;
2171 /* Check for no more than one talker */
2172 if ((join_isoch_info
->jii_options
& T1394_TALKER
) &&
2173 (cec_curr
->cec_member_talker
!= NULL
)) {
2174 kmem_free(member_new
, sizeof (s1394_isoch_cec_member_t
));
2175 /* Unlock the Isoch CEC member list */
2176 mutex_exit(&cec_curr
->isoch_cec_mutex
);
2177 TNF_PROBE_1(t1394_join_isoch_cec_error
,
2178 S1394_TNF_SL_ISOCH_ERROR
, "", tnf_string
, msg
,
2179 "Multiple talkers specified");
2180 TNF_PROBE_0_DEBUG(t1394_join_isoch_cec_exit
,
2181 S1394_TNF_SL_ISOCH_STACK
, "");
2182 return (DDI_FAILURE
);
2185 /* Verify that all callbacks are non-NULL (for PEER_TO_PEER) */
2186 if ((cec_curr
->cec_type
== S1394_PEER_TO_PEER
) &&
2187 ((join_isoch_info
->isoch_cec_evts
.setup_target
== NULL
) ||
2188 (join_isoch_info
->isoch_cec_evts
.start_target
== NULL
) ||
2189 (join_isoch_info
->isoch_cec_evts
.stop_target
== NULL
) ||
2190 (join_isoch_info
->isoch_cec_evts
.rsrc_fail_target
== NULL
) ||
2191 (join_isoch_info
->isoch_cec_evts
.teardown_target
== NULL
))) {
2192 /* Unlock the Isoch CEC member list */
2193 mutex_exit(&cec_curr
->isoch_cec_mutex
);
2194 TNF_PROBE_1(t1394_join_isoch_cec_error
,
2195 S1394_TNF_SL_ISOCH_ERROR
, "", tnf_string
, msg
,
2196 "Invalid callbacks specified");
2197 TNF_PROBE_0_DEBUG(t1394_join_isoch_cec_exit
,
2198 S1394_TNF_SL_ISOCH_STACK
, "");
2199 return (DDI_FAILURE
);
2202 /* Copy the events information into the struct */
2203 member_new
->isoch_cec_evts
= join_isoch_info
->isoch_cec_evts
;
2204 member_new
->isoch_cec_evts_arg
= join_isoch_info
->isoch_cec_evts_arg
;
2205 member_new
->cec_mem_options
= join_isoch_info
->jii_options
;
2206 member_new
->cec_mem_target
= (s1394_target_t
*)t1394_hdl
;
2208 /* Insert new member into Isoch CEC's member list */
2209 s1394_isoch_cec_member_list_insert(hal
, cec_curr
, member_new
);
2211 /* Update the channel mask filter */
2212 cec_curr
->filter_channel_mask
= check_mask
;
2214 /* Update the speed filter */
2215 cec_curr
->filter_current_speed
= curr_max_speed
;
2217 /* Update the talker pointer (if necessary) */
2218 if (join_isoch_info
->jii_options
& T1394_TALKER
)
2219 cec_curr
->cec_member_talker
= cec_curr
->cec_member_list_head
;
2222 * Now "leave" is a legal state transition
2223 * and "free" is an illegal state transition
2225 CEC_SET_LEGAL(cec_curr
, ISOCH_CEC_LEAVE
);
2226 CEC_SET_ILLEGAL(cec_curr
, ISOCH_CEC_FREE
);
2228 /* Unlock the Isoch CEC member list */
2229 mutex_exit(&cec_curr
->isoch_cec_mutex
);
2231 TNF_PROBE_0_DEBUG(t1394_join_isoch_cec_exit
,
2232 S1394_TNF_SL_ISOCH_STACK
, "");
2233 return (DDI_SUCCESS
);
2237 * Function: t1394_leave_isoch_cec()
2238 * Input(s): t1394_hdl The target "handle" returned by
2240 * t1394_isoch_cec_hdl The Isoch CEC "handle" returned by
2241 * t1394_alloc_isoch_cec()
2242 * flags The flags parameter is unused (for now)
2244 * Output(s): DDI_SUCCESS Target successfully left the
2246 * DDI_FAILURE Target failed to leave the Isoch CEC
2248 * Description: t1394_leave_isoch_cec() is used by a target driver to remove
2249 * itself from the Isoch CEC's member list. It is possible
2250 * for this call to fail because the target is not found in
2251 * the current member list, or because it is not an appropriate
2252 * time for a target to leave.
2256 t1394_leave_isoch_cec(t1394_handle_t t1394_hdl
,
2257 t1394_isoch_cec_handle_t t1394_isoch_cec_hdl
, uint_t flags
)
2260 s1394_isoch_cec_t
*cec_curr
;
2261 s1394_isoch_cec_member_t
*member_curr
;
2262 s1394_isoch_cec_member_t
*member_temp
;
2264 uint64_t temp_channel_mask
;
2265 uint_t temp_max_speed
;
2267 TNF_PROBE_0_DEBUG(t1394_leave_isoch_cec_enter
,
2268 S1394_TNF_SL_ISOCH_STACK
, "");
2270 ASSERT(t1394_hdl
!= NULL
);
2271 ASSERT(t1394_isoch_cec_hdl
!= NULL
);
2273 hal
= ((s1394_target_t
*)t1394_hdl
)->on_hal
;
2275 /* Convert the handle to an Isoch CEC pointer */
2276 cec_curr
= (s1394_isoch_cec_t
*)t1394_isoch_cec_hdl
;
2278 /* Lock the Isoch CEC member list */
2279 mutex_enter(&cec_curr
->isoch_cec_mutex
);
2281 /* Are we in any callbacks? (Wait for them to finish) */
2282 while (CEC_IN_ANY_CALLBACKS(cec_curr
)) {
2283 cec_curr
->cec_want_wakeup
= B_TRUE
;
2284 cv_wait(&cec_curr
->in_callbacks_cv
,
2285 &cec_curr
->isoch_cec_mutex
);
2288 /* Is "leave" a legal state transition? */
2289 if (CEC_TRANSITION_LEGAL(cec_curr
, ISOCH_CEC_LEAVE
) == 0) {
2290 /* Unlock the Isoch CEC member list */
2291 mutex_exit(&cec_curr
->isoch_cec_mutex
);
2292 TNF_PROBE_1(t1394_leave_isoch_cec_error
,
2293 S1394_TNF_SL_ISOCH_ERROR
, "", tnf_string
, msg
,
2294 "Not allowed to leave Isoch CEC");
2295 TNF_PROBE_0_DEBUG(t1394_leave_isoch_cec_exit
,
2296 S1394_TNF_SL_ISOCH_STACK
, "");
2297 return (DDI_FAILURE
);
2300 /* Find the Target on the CEC's member list */
2302 temp_channel_mask
= cec_curr
->cec_alloc_props
.cec_channel_mask
;
2303 temp_max_speed
= cec_curr
->cec_alloc_props
.cec_max_speed
;
2304 member_curr
= cec_curr
->cec_member_list_head
;
2305 while (member_curr
!= NULL
) {
2306 if (member_curr
->cec_mem_target
==
2307 (s1394_target_t
*)t1394_hdl
) {
2308 member_temp
= member_curr
;
2311 /* Keep track of channel mask and max speed info */
2312 temp_channel_mask
&= member_curr
->req_channel_mask
;
2313 if (member_curr
->req_max_speed
< temp_max_speed
)
2314 temp_max_speed
= member_curr
->req_max_speed
;
2316 member_curr
= member_curr
->cec_mem_next
;
2319 /* Target not found on this Isoch CEC */
2320 if (found
== B_FALSE
) {
2321 /* Unlock the Isoch CEC member list */
2322 mutex_exit(&cec_curr
->isoch_cec_mutex
);
2323 TNF_PROBE_1(t1394_leave_isoch_cec_error
,
2324 S1394_TNF_SL_ISOCH_ERROR
, "", tnf_string
, msg
,
2325 "Target not found in Isoch CEC member list");
2326 TNF_PROBE_0_DEBUG(t1394_leave_isoch_cec_exit
,
2327 S1394_TNF_SL_ISOCH_STACK
, "");
2328 return (DDI_FAILURE
);
2330 /* This member's departure may change filter constraints */
2331 cec_curr
->filter_current_speed
= temp_max_speed
;
2332 cec_curr
->filter_channel_mask
= temp_channel_mask
;
2335 /* Remove member from Isoch CEC's member list */
2336 s1394_isoch_cec_member_list_remove(hal
, cec_curr
, member_temp
);
2338 /* If we are removing the talker, then update the pointer */
2339 if (cec_curr
->cec_member_talker
== member_temp
)
2340 cec_curr
->cec_member_talker
= NULL
;
2342 /* Is the Isoch CEC's member list empty? */
2343 if ((cec_curr
->cec_member_list_head
== NULL
) &&
2344 (cec_curr
->cec_member_list_tail
== NULL
)) {
2346 * Now "free" _might_ be a legal state transition
2347 * if we aren't in setup or start phases and "leave"
2348 * is definitely an illegal state transition
2350 if (CEC_TRANSITION_LEGAL(cec_curr
, ISOCH_CEC_JOIN
) != 0)
2351 CEC_SET_LEGAL(cec_curr
, ISOCH_CEC_FREE
);
2352 CEC_SET_ILLEGAL(cec_curr
, ISOCH_CEC_LEAVE
);
2355 /* Unlock the Isoch CEC member list */
2356 mutex_exit(&cec_curr
->isoch_cec_mutex
);
2358 /* Free the Isoch CEC member structure */
2359 kmem_free(member_temp
, sizeof (s1394_isoch_cec_member_t
));
2361 TNF_PROBE_0_DEBUG(t1394_leave_isoch_cec_exit
,
2362 S1394_TNF_SL_ISOCH_STACK
, "");
2363 return (DDI_SUCCESS
);
2367 * Function: t1394_setup_isoch_cec()
2368 * Input(s): t1394_hdl The target "handle" returned by
2370 * t1394_isoch_cec_hdl The Isoch CEC "handle" returned by
2371 * t1394_alloc_isoch_cec()
2372 * flags The flags parameter is unused (for now)
2374 * Output(s): result Used to pass more specific info back
2377 * Description: t1394_setup_isoch_cec() directs the 1394 Software Framework
2378 * to allocate isochronous resources and invoke the setup_target()
2379 * callback for each member of the Isoch CEC. This call may
2380 * fail because bandwidth was unavailable (T1394_ENO_BANDWIDTH),
2381 * channels were unavailable (T1394_ENO_CHANNEL), or one of the
2382 * member targets returned failure from its setup_target()
2387 t1394_setup_isoch_cec(t1394_handle_t t1394_hdl
,
2388 t1394_isoch_cec_handle_t t1394_isoch_cec_hdl
, uint_t flags
, int *result
)
2391 s1394_isoch_cec_t
*cec_curr
;
2392 s1394_isoch_cec_member_t
*member_curr
;
2393 t1394_setup_target_args_t target_args
;
2394 uint64_t temp_chnl_mask
;
2397 uint_t bw_alloc_units
;
2403 int (*setup_callback
)(t1394_isoch_cec_handle_t
, opaque_t
,
2404 t1394_setup_target_args_t
*);
2406 TNF_PROBE_0_DEBUG(t1394_setup_isoch_cec_enter
,
2407 S1394_TNF_SL_ISOCH_STACK
, "");
2409 ASSERT(t1394_hdl
!= NULL
);
2410 ASSERT(t1394_isoch_cec_hdl
!= NULL
);
2412 hal
= ((s1394_target_t
*)t1394_hdl
)->on_hal
;
2414 /* Convert the handle to an Isoch CEC pointer */
2415 cec_curr
= (s1394_isoch_cec_t
*)t1394_isoch_cec_hdl
;
2417 /* Lock the Isoch CEC member list */
2418 mutex_enter(&cec_curr
->isoch_cec_mutex
);
2420 /* Are we in any callbacks? */
2421 if (CEC_IN_ANY_CALLBACKS(cec_curr
)) {
2422 /* Unlock the Isoch CEC member list */
2423 mutex_exit(&cec_curr
->isoch_cec_mutex
);
2424 TNF_PROBE_1(t1394_setup_isoch_cec_error
,
2425 S1394_TNF_SL_ISOCH_ERROR
, "", tnf_string
, msg
,
2426 "Not allowed to setup Isoch CEC (in callbacks)");
2427 TNF_PROBE_0_DEBUG(t1394_setup_isoch_cec_exit
,
2428 S1394_TNF_SL_ISOCH_STACK
, "");
2429 return (DDI_FAILURE
);
2432 /* Is "setup" a legal state transition? */
2433 if (CEC_TRANSITION_LEGAL(cec_curr
, ISOCH_CEC_SETUP
) == 0) {
2434 /* Unlock the Isoch CEC member list */
2435 mutex_exit(&cec_curr
->isoch_cec_mutex
);
2436 TNF_PROBE_1(t1394_setup_isoch_cec_error
,
2437 S1394_TNF_SL_ISOCH_ERROR
, "", tnf_string
, msg
,
2438 "Not allowed to setup Isoch CEC");
2439 TNF_PROBE_0_DEBUG(t1394_setup_isoch_cec_exit
,
2440 S1394_TNF_SL_ISOCH_STACK
, "");
2441 return (DDI_FAILURE
);
2444 /* If T1394_NO_IRM_ALLOC is set then don't allocate... do callbacks */
2445 if (cec_curr
->cec_options
& T1394_NO_IRM_ALLOC
) {
2446 goto setup_do_callbacks
;
2449 /* Allocate bandwidth and channels */
2450 for (j
= 0; j
< S1394_ISOCH_ALLOC_RETRIES
; j
++) {
2452 * Get the current generation number - don't
2453 * need the lock because we are read only here
2455 generation
= hal
->generation_count
;
2457 /* Compute how much bandwidth is needed */
2458 bw_alloc_units
= s1394_compute_bw_alloc_units(hal
,
2459 cec_curr
->bandwidth
, cec_curr
->filter_current_speed
);
2461 /* Check that the generation has not changed - */
2462 /* don't need the lock (read only) */
2463 if (generation
!= hal
->generation_count
)
2466 /* Unlock the Isoch CEC member list */
2467 mutex_exit(&cec_curr
->isoch_cec_mutex
);
2469 /* Try to allocate the bandwidth */
2470 ret
= s1394_bandwidth_alloc(hal
, bw_alloc_units
, generation
,
2473 /* Lock the Isoch CEC member list */
2474 mutex_enter(&cec_curr
->isoch_cec_mutex
);
2476 /* If there was a bus reset, start over */
2477 if (ret
== DDI_FAILURE
) {
2478 if (err
== CMD1394_EBUSRESET
) {
2479 continue; /* start over and try again */
2481 *result
= T1394_ENO_BANDWIDTH
;
2482 /* Unlock the Isoch CEC member list */
2483 mutex_exit(&cec_curr
->isoch_cec_mutex
);
2484 TNF_PROBE_1(t1394_setup_isoch_cec_error
,
2485 S1394_TNF_SL_ISOCH_ERROR
, "", tnf_string
,
2486 msg
, "Unable to allocate isoch bandwidth");
2487 TNF_PROBE_0_DEBUG(t1394_setup_isoch_cec_exit
,
2488 S1394_TNF_SL_ISOCH_STACK
, "");
2489 return (DDI_FAILURE
);
2493 /* Check that the generation has not changed - */
2494 /* don't need the lock (read only) */
2495 if (generation
!= hal
->generation_count
)
2499 * Allocate a channel
2500 * From IEEE 1394-1995, Section 8.3.2.3.8: "Bits
2501 * allocated in the CHANNELS_AVAILABLE_HI field of
2502 * this register shall start at bit zero (channel
2503 * number zero), and additional channel numbers shall
2504 * be represented in a monotonically increasing sequence
2505 * of bit numbers up to a maximum of bit 31 (channel
2506 * number 31). Bits allocated in the CHANNELS_AVAILABLE_LO
2507 * field of this register shall start at bit zero
2508 * (channel number 32), and additional channel numbers
2509 * shall be represented in a monotonically increasing
2510 * sequence of bit numbers up to a maximum of bit 31
2511 * (channel number 63).
2513 temp_chnl_mask
= cec_curr
->filter_channel_mask
;
2514 for (chnl_num
= 63; chnl_num
>= 0; chnl_num
--) {
2515 if ((temp_chnl_mask
& 1) == 1) {
2516 try_chnl
= (1 << ((63 - chnl_num
) % 32));
2518 /* Unlock the Isoch CEC member list */
2519 mutex_exit(&cec_curr
->isoch_cec_mutex
);
2520 if (chnl_num
< 32) {
2521 ret
= s1394_channel_alloc(hal
,
2522 try_chnl
, generation
,
2523 S1394_CHANNEL_ALLOC_HI
, &old_chnl
,
2526 ret
= s1394_channel_alloc(hal
,
2527 try_chnl
, generation
,
2528 S1394_CHANNEL_ALLOC_LO
, &old_chnl
,
2531 /* Lock the Isoch CEC member list */
2532 mutex_enter(&cec_curr
->isoch_cec_mutex
);
2534 /* Did we get a channel? (or a bus reset) */
2535 if ((ret
== DDI_SUCCESS
) ||
2536 (err
== CMD1394_EBUSRESET
))
2539 temp_chnl_mask
= temp_chnl_mask
>> 1;
2542 /* If we've tried all the possible channels, then fail */
2543 if (chnl_num
== 0) {
2544 *result
= T1394_ENO_CHANNEL
;
2546 * If we successfully allocate bandwidth, and
2547 * then fail getting a channel, we need to
2548 * free up the bandwidth
2551 /* Check that the generation has not changed */
2552 /* lock not needed here (read only) */
2553 if (generation
!= hal
->generation_count
)
2556 /* Unlock the Isoch CEC member list */
2557 mutex_exit(&cec_curr
->isoch_cec_mutex
);
2559 /* Try to free up the bandwidth */
2560 ret
= s1394_bandwidth_free(hal
, bw_alloc_units
,
2563 /* Lock the Isoch CEC member list */
2564 mutex_enter(&cec_curr
->isoch_cec_mutex
);
2566 if (ret
== DDI_FAILURE
) {
2567 if (err
== CMD1394_EBUSRESET
) {
2570 TNF_PROBE_1(t1394_setup_isoch_cec_error
,
2571 S1394_TNF_SL_ISOCH_ERROR
, "",
2573 "Unable to free isoch bandwidth");
2577 /* Unlock the Isoch CEC member list */
2578 mutex_exit(&cec_curr
->isoch_cec_mutex
);
2579 TNF_PROBE_1(t1394_setup_isoch_cec_error
,
2580 S1394_TNF_SL_ISOCH_ERROR
, "", tnf_string
, msg
,
2581 "Unable to allocate isoch channel");
2582 TNF_PROBE_0_DEBUG(t1394_setup_isoch_cec_exit
,
2583 S1394_TNF_SL_ISOCH_STACK
, "");
2584 return (DDI_FAILURE
);
2587 /* If we got a channel, we're done (else start over) */
2588 if (ret
== DDI_SUCCESS
)
2590 else if (err
== CMD1394_EBUSRESET
)
2594 /* Have we gotten too many bus resets? */
2595 if (j
== S1394_ISOCH_ALLOC_RETRIES
) {
2596 *result
= T1394_ENO_BANDWIDTH
;
2597 /* Unlock the Isoch CEC member list */
2598 mutex_exit(&cec_curr
->isoch_cec_mutex
);
2599 TNF_PROBE_1(t1394_setup_isoch_cec_error
,
2600 S1394_TNF_SL_ISOCH_ERROR
, "", tnf_string
, msg
,
2601 "Unable to allocate isoch channel");
2602 TNF_PROBE_0_DEBUG(t1394_setup_isoch_cec_exit
,
2603 S1394_TNF_SL_ISOCH_STACK
, "");
2604 return (DDI_FAILURE
);
2607 cec_curr
->realloc_valid
= B_TRUE
;
2608 cec_curr
->realloc_chnl_num
= chnl_num
;
2609 cec_curr
->realloc_bandwidth
= cec_curr
->bandwidth
;
2610 cec_curr
->realloc_speed
= cec_curr
->filter_current_speed
;
2613 /* Call all of the setup_target() callbacks */
2614 target_args
.channel_num
= chnl_num
;
2615 target_args
.channel_speed
= cec_curr
->filter_current_speed
;
2617 /* Now we are going into the callbacks */
2618 cec_curr
->in_callbacks
= B_TRUE
;
2620 /* Unlock the Isoch CEC member list */
2621 mutex_exit(&cec_curr
->isoch_cec_mutex
);
2623 member_curr
= cec_curr
->cec_member_list_head
;
2625 while (member_curr
!= NULL
) {
2626 if (member_curr
->isoch_cec_evts
.setup_target
!= NULL
) {
2628 member_curr
->isoch_cec_evts
.setup_target
;
2629 ret
= setup_callback(t1394_isoch_cec_hdl
,
2630 member_curr
->isoch_cec_evts_arg
, &target_args
);
2631 if (ret
!= DDI_SUCCESS
)
2632 *result
= T1394_ETARGET
;
2634 member_curr
= member_curr
->cec_mem_next
;
2637 /* Lock the Isoch CEC member list */
2638 mutex_enter(&cec_curr
->isoch_cec_mutex
);
2640 /* We are finished with the callbacks */
2641 cec_curr
->in_callbacks
= B_FALSE
;
2642 if (cec_curr
->cec_want_wakeup
== B_TRUE
) {
2643 cec_curr
->cec_want_wakeup
= B_FALSE
;
2644 cv_broadcast(&cec_curr
->in_callbacks_cv
);
2648 * Now "start" and "teardown" are legal state transitions
2649 * and "join", "free", and "setup" are illegal state transitions
2651 CEC_SET_LEGAL(cec_curr
, (ISOCH_CEC_START
| ISOCH_CEC_TEARDOWN
));
2652 CEC_SET_ILLEGAL(cec_curr
, (ISOCH_CEC_JOIN
| ISOCH_CEC_FREE
|
2655 /* Unlock the Isoch CEC member list */
2656 mutex_exit(&cec_curr
->isoch_cec_mutex
);
2658 /* Return DDI_FAILURE if any targets failed setup */
2660 TNF_PROBE_1(t1394_setup_isoch_cec_error
,
2661 S1394_TNF_SL_ISOCH_ERROR
, "", tnf_string
, msg
,
2662 "Target returned error in setup_target()");
2663 TNF_PROBE_0_DEBUG(t1394_setup_isoch_cec_exit
,
2664 S1394_TNF_SL_ISOCH_STACK
, "");
2665 return (DDI_FAILURE
);
2668 TNF_PROBE_0_DEBUG(t1394_setup_isoch_cec_exit
,
2669 S1394_TNF_SL_ISOCH_STACK
, "");
2670 return (DDI_SUCCESS
);
2674 * Function: t1394_start_isoch_cec()
2675 * Input(s): t1394_hdl The target "handle" returned by
2677 * t1394_isoch_cec_hdl The Isoch CEC "handle" returned by
2678 * t1394_alloc_isoch_cec()
2679 * flags The flags parameter is unused (for now)
2681 * Output(s): DDI_SUCCESS All start_target() callbacks returned
2683 * DDI_FAILURE One or more start_target() callbacks
2686 * Description: t1394_start_isoch_cec() directs the 1394 Software Framework
2687 * to invoke each of the start_target() callbacks, first for
2688 * each listener, then for the talker.
2692 t1394_start_isoch_cec(t1394_handle_t t1394_hdl
,
2693 t1394_isoch_cec_handle_t t1394_isoch_cec_hdl
, uint_t flags
)
2695 s1394_isoch_cec_t
*cec_curr
;
2696 s1394_isoch_cec_member_t
*member_curr
;
2699 int (*start_callback
)(t1394_isoch_cec_handle_t
, opaque_t
);
2701 TNF_PROBE_0_DEBUG(t1394_start_isoch_cec_enter
,
2702 S1394_TNF_SL_ISOCH_STACK
, "");
2704 ASSERT(t1394_hdl
!= NULL
);
2705 ASSERT(t1394_isoch_cec_hdl
!= NULL
);
2707 /* Convert the handle to an Isoch CEC pointer */
2708 cec_curr
= (s1394_isoch_cec_t
*)t1394_isoch_cec_hdl
;
2710 /* Lock the Isoch CEC member list */
2711 mutex_enter(&cec_curr
->isoch_cec_mutex
);
2713 /* Are we in any callbacks? */
2714 if (CEC_IN_ANY_CALLBACKS(cec_curr
)) {
2715 /* Unlock the Isoch CEC member list */
2716 mutex_exit(&cec_curr
->isoch_cec_mutex
);
2717 TNF_PROBE_1(t1394_start_isoch_cec_error
,
2718 S1394_TNF_SL_ISOCH_ERROR
, "", tnf_string
, msg
,
2719 "Not allowed to start Isoch CEC (in callbacks)");
2720 TNF_PROBE_0_DEBUG(t1394_start_isoch_cec_exit
,
2721 S1394_TNF_SL_ISOCH_STACK
, "");
2722 return (DDI_FAILURE
);
2725 /* Is "start" a legal state transition? */
2726 if (CEC_TRANSITION_LEGAL(cec_curr
, ISOCH_CEC_START
) == 0) {
2727 /* Unlock the Isoch CEC member list */
2728 mutex_exit(&cec_curr
->isoch_cec_mutex
);
2729 TNF_PROBE_1(t1394_start_isoch_cec_error
,
2730 S1394_TNF_SL_ISOCH_ERROR
, "", tnf_string
, msg
,
2731 "Not allowed to start Isoch CEC");
2732 TNF_PROBE_0_DEBUG(t1394_start_isoch_cec_exit
,
2733 S1394_TNF_SL_ISOCH_STACK
, "");
2734 return (DDI_FAILURE
);
2737 /* Now we are going into the callbacks */
2738 cec_curr
->in_callbacks
= B_TRUE
;
2740 /* Unlock the Isoch CEC member list */
2741 mutex_exit(&cec_curr
->isoch_cec_mutex
);
2744 * Call all of the start_target() callbacks
2745 * Start at the tail (listeners first) and
2746 * go toward the head (talker last)
2748 member_curr
= cec_curr
->cec_member_list_tail
;
2750 while (member_curr
!= NULL
) {
2751 if (member_curr
->isoch_cec_evts
.start_target
!= NULL
) {
2753 member_curr
->isoch_cec_evts
.start_target
;
2754 ret
= start_callback(t1394_isoch_cec_hdl
,
2755 member_curr
->isoch_cec_evts_arg
);
2756 if (ret
!= DDI_SUCCESS
)
2759 member_curr
= member_curr
->cec_mem_prev
;
2762 /* Lock the Isoch CEC member list */
2763 mutex_enter(&cec_curr
->isoch_cec_mutex
);
2765 /* We are finished with the callbacks */
2766 cec_curr
->in_callbacks
= B_FALSE
;
2767 if (cec_curr
->cec_want_wakeup
== B_TRUE
) {
2768 cec_curr
->cec_want_wakeup
= B_FALSE
;
2769 cv_broadcast(&cec_curr
->in_callbacks_cv
);
2773 * Now "stop" is a legal state transitions
2774 * and "start" and "teardown" are illegal state transitions
2776 CEC_SET_LEGAL(cec_curr
, ISOCH_CEC_STOP
);
2777 CEC_SET_ILLEGAL(cec_curr
, (ISOCH_CEC_START
| ISOCH_CEC_TEARDOWN
));
2779 /* Unlock the Isoch CEC member list */
2780 mutex_exit(&cec_curr
->isoch_cec_mutex
);
2782 /* Return DDI_FAILURE if any targets failed start */
2783 if (err
== B_TRUE
) {
2784 TNF_PROBE_1(t1394_start_isoch_cec_error
,
2785 S1394_TNF_SL_ISOCH_ERROR
, "", tnf_string
, msg
,
2786 "Target returned error in start_target()");
2787 TNF_PROBE_0_DEBUG(t1394_start_isoch_cec_exit
,
2788 S1394_TNF_SL_ISOCH_STACK
, "");
2789 return (DDI_FAILURE
);
2792 TNF_PROBE_0_DEBUG(t1394_start_isoch_cec_exit
,
2793 S1394_TNF_SL_ISOCH_STACK
, "");
2794 return (DDI_SUCCESS
);
2798 * Function: t1394_stop_isoch_cec()
2799 * Input(s): t1394_hdl The target "handle" returned by
2801 * t1394_isoch_cec_hdl The Isoch CEC "handle" returned by
2802 * t1394_alloc_isoch_cec()
2803 * flags The flags parameter is unused (for now)
2805 * Output(s): DDI_SUCCESS Target successfully stopped the
2807 * DDI_FAILURE Target failed to stop the Isoch CEC
2809 * Description: t1394_stop_isoch_cec() directs the 1394 Software Framework
2810 * to invoke each of the stop_target() callbacks, first for
2811 * the talker, then for each listener.
2812 * (This call will fail if it is called at an
2813 * inappropriate time, i.e. before the t1394_start_isoch_cec()
2818 t1394_stop_isoch_cec(t1394_handle_t t1394_hdl
,
2819 t1394_isoch_cec_handle_t t1394_isoch_cec_hdl
, uint_t flags
)
2821 s1394_isoch_cec_t
*cec_curr
;
2822 s1394_isoch_cec_member_t
*member_curr
;
2823 void (*stop_callback
)(t1394_isoch_cec_handle_t
, opaque_t
);
2825 TNF_PROBE_0_DEBUG(t1394_stop_isoch_cec_enter
,
2826 S1394_TNF_SL_ISOCH_STACK
, "");
2828 ASSERT(t1394_hdl
!= NULL
);
2829 ASSERT(t1394_isoch_cec_hdl
!= NULL
);
2831 /* Convert the handle to an Isoch CEC pointer */
2832 cec_curr
= (s1394_isoch_cec_t
*)t1394_isoch_cec_hdl
;
2834 /* Lock the Isoch CEC member list */
2835 mutex_enter(&cec_curr
->isoch_cec_mutex
);
2837 /* Are we in any callbacks? */
2838 if (CEC_IN_ANY_CALLBACKS(cec_curr
)) {
2839 /* Unlock the Isoch CEC member list */
2840 mutex_exit(&cec_curr
->isoch_cec_mutex
);
2841 TNF_PROBE_1(t1394_stop_isoch_cec_error
,
2842 S1394_TNF_SL_ISOCH_ERROR
, "", tnf_string
, msg
,
2843 "Not allowed to stop Isoch CEC (in callbacks)");
2844 TNF_PROBE_0_DEBUG(t1394_stop_isoch_cec_exit
,
2845 S1394_TNF_SL_ISOCH_STACK
, "");
2846 return (DDI_FAILURE
);
2849 /* Is "stop" a legal state transition? */
2850 if (CEC_TRANSITION_LEGAL(cec_curr
, ISOCH_CEC_STOP
) == 0) {
2851 /* Unlock the Isoch CEC member list */
2852 mutex_exit(&cec_curr
->isoch_cec_mutex
);
2853 TNF_PROBE_1(t1394_stop_isoch_cec_error
,
2854 S1394_TNF_SL_ISOCH_ERROR
, "", tnf_string
, msg
,
2855 "Not allowed to stop Isoch CEC");
2856 TNF_PROBE_0_DEBUG(t1394_stop_isoch_cec_exit
,
2857 S1394_TNF_SL_ISOCH_STACK
, "");
2858 return (DDI_FAILURE
);
2861 /* Now we are going into the callbacks */
2862 cec_curr
->in_callbacks
= B_TRUE
;
2864 /* Unlock the Isoch CEC member list */
2865 mutex_exit(&cec_curr
->isoch_cec_mutex
);
2868 * Call all of the stop_target() callbacks
2869 * Start at the head (talker first) and
2870 * go toward the tail (listeners last)
2872 member_curr
= cec_curr
->cec_member_list_head
;
2873 while (member_curr
!= NULL
) {
2874 if (member_curr
->isoch_cec_evts
.stop_target
!= NULL
) {
2876 member_curr
->isoch_cec_evts
.stop_target
;
2877 stop_callback(t1394_isoch_cec_hdl
,
2878 member_curr
->isoch_cec_evts_arg
);
2880 member_curr
= member_curr
->cec_mem_next
;
2883 /* Lock the Isoch CEC member list */
2884 mutex_enter(&cec_curr
->isoch_cec_mutex
);
2886 /* We are finished with the callbacks */
2887 cec_curr
->in_callbacks
= B_FALSE
;
2888 if (cec_curr
->cec_want_wakeup
== B_TRUE
) {
2889 cec_curr
->cec_want_wakeup
= B_FALSE
;
2890 cv_broadcast(&cec_curr
->in_callbacks_cv
);
2894 * Now "start" and "teardown" are legal state transitions
2895 * and "stop" is an illegal state transitions
2897 CEC_SET_LEGAL(cec_curr
, (ISOCH_CEC_START
| ISOCH_CEC_TEARDOWN
));
2898 CEC_SET_ILLEGAL(cec_curr
, ISOCH_CEC_STOP
);
2900 /* Unlock the Isoch CEC member list */
2901 mutex_exit(&cec_curr
->isoch_cec_mutex
);
2903 TNF_PROBE_0_DEBUG(t1394_stop_isoch_cec_exit
,
2904 S1394_TNF_SL_ISOCH_STACK
, "");
2905 return (DDI_SUCCESS
);
2909 * Function: t1394_teardown_isoch_cec()
2910 * Input(s): t1394_hdl The target "handle" returned by
2912 * t1394_isoch_cec_hdl The Isoch CEC "handle" returned by
2913 * t1394_alloc_isoch_cec()
2914 * flags The flags parameter is unused (for now)
2916 * Output(s): DDI_SUCCESS Target successfully tore down the
2918 * DDI_FAILURE Target failed to tear down the
2921 * Description: t1394_teardown_isoch_cec() directs the 1394 Software Framework
2922 * to free up any isochronous resources we might be holding and
2923 * call all of the teardown_target() callbacks.
2924 * (This call will fail if it is called at an
2925 * inappropriate time, i.e. before the t1394_start_isoch_cec()
2926 * call, before the t1394_stop_isoch_cec, etc.
2930 t1394_teardown_isoch_cec(t1394_handle_t t1394_hdl
,
2931 t1394_isoch_cec_handle_t t1394_isoch_cec_hdl
, uint_t flags
)
2934 s1394_isoch_cec_t
*cec_curr
;
2935 s1394_isoch_cec_member_t
*member_curr
;
2937 uint32_t old_chnl_mask
;
2938 uint_t bw_alloc_units
;
2942 void (*teardown_callback
)(t1394_isoch_cec_handle_t
, opaque_t
);
2944 TNF_PROBE_0_DEBUG(t1394_teardown_isoch_cec_enter
,
2945 S1394_TNF_SL_ISOCH_STACK
, "");
2947 ASSERT(t1394_hdl
!= NULL
);
2948 ASSERT(t1394_isoch_cec_hdl
!= NULL
);
2950 hal
= ((s1394_target_t
*)t1394_hdl
)->on_hal
;
2952 /* Convert the handle to an Isoch CEC pointer */
2953 cec_curr
= (s1394_isoch_cec_t
*)t1394_isoch_cec_hdl
;
2955 /* Lock the Isoch CEC member list */
2956 mutex_enter(&cec_curr
->isoch_cec_mutex
);
2958 /* Are we in any callbacks? */
2959 if (CEC_IN_ANY_CALLBACKS(cec_curr
)) {
2960 /* Unlock the Isoch CEC member list */
2961 mutex_exit(&cec_curr
->isoch_cec_mutex
);
2962 TNF_PROBE_1(t1394_teardown_isoch_cec_error
,
2963 S1394_TNF_SL_ISOCH_ERROR
, "", tnf_string
, msg
,
2964 "Not allowed to teardown Isoch CEC (in callbacks)");
2965 TNF_PROBE_0_DEBUG(t1394_teardown_isoch_cec_exit
,
2966 S1394_TNF_SL_ISOCH_STACK
, "");
2967 return (DDI_FAILURE
);
2970 /* Is "teardown" a legal state transition? */
2971 if (CEC_TRANSITION_LEGAL(cec_curr
, ISOCH_CEC_TEARDOWN
) == 0) {
2972 /* Unlock the Isoch CEC member list */
2973 mutex_exit(&cec_curr
->isoch_cec_mutex
);
2974 TNF_PROBE_1(t1394_teardown_isoch_cec_error
,
2975 S1394_TNF_SL_ISOCH_ERROR
, "", tnf_string
, msg
,
2976 "Not allowed to teardown Isoch CEC");
2977 TNF_PROBE_0_DEBUG(t1394_teardown_isoch_cec_exit
,
2978 S1394_TNF_SL_ISOCH_STACK
, "");
2979 return (DDI_FAILURE
);
2982 /* If T1394_NO_IRM_ALLOC is set then don't free... do callbacks */
2983 if (cec_curr
->cec_options
& T1394_NO_IRM_ALLOC
) {
2984 goto teardown_do_callbacks
;
2987 /* If nothing has been allocated or we failed to */
2988 /* reallocate, then we are done... call the callbacks */
2989 if ((cec_curr
->realloc_valid
== B_FALSE
) ||
2990 (cec_curr
->realloc_failed
== B_TRUE
)) {
2991 goto teardown_do_callbacks
;
2995 * Get the current generation number - don't need the
2996 * topology tree mutex here because it is read-only, and
2997 * there is a race condition with or without it.
2999 generation
= hal
->generation_count
;
3001 /* Compute the amount bandwidth to free */
3002 bw_alloc_units
= s1394_compute_bw_alloc_units(hal
,
3003 cec_curr
->bandwidth
, cec_curr
->realloc_speed
);
3005 /* Check that the generation has not changed - */
3006 /* don't need the lock (read only) */
3007 if (generation
!= hal
->generation_count
)
3008 goto teardown_do_callbacks
;
3010 /* Unlock the Isoch CEC member list */
3011 mutex_exit(&cec_curr
->isoch_cec_mutex
);
3013 /* Try to free up the bandwidth */
3014 ret
= s1394_bandwidth_free(hal
, bw_alloc_units
, generation
, &err
);
3016 /* Lock the Isoch CEC member list */
3017 mutex_enter(&cec_curr
->isoch_cec_mutex
);
3019 if (ret
== DDI_FAILURE
) {
3020 if (err
== CMD1394_EBUSRESET
) {
3021 goto teardown_do_callbacks
;
3023 TNF_PROBE_1(t1394_teardown_isoch_cec_error
,
3024 S1394_TNF_SL_ISOCH_ERROR
, "", tnf_string
, msg
,
3025 "Unable to free allocated bandwidth");
3029 /* Free the allocated channel */
3030 chnl_mask
= (1 << ((63 - cec_curr
->realloc_chnl_num
) % 32));
3032 /* Unlock the Isoch CEC member list */
3033 mutex_exit(&cec_curr
->isoch_cec_mutex
);
3034 if (cec_curr
->realloc_chnl_num
< 32) {
3035 ret
= s1394_channel_free(hal
, chnl_mask
, generation
,
3036 S1394_CHANNEL_ALLOC_HI
, &old_chnl_mask
, &err
);
3038 ret
= s1394_channel_free(hal
, chnl_mask
, generation
,
3039 S1394_CHANNEL_ALLOC_LO
, &old_chnl_mask
, &err
);
3041 /* Lock the Isoch CEC member list */
3042 mutex_enter(&cec_curr
->isoch_cec_mutex
);
3044 if (ret
== DDI_FAILURE
) {
3045 if (err
== CMD1394_EBUSRESET
) {
3046 goto teardown_do_callbacks
;
3048 TNF_PROBE_1(t1394_teardown_isoch_cec_error
,
3049 S1394_TNF_SL_ISOCH_ERROR
, "", tnf_string
, msg
,
3050 "Unable to free allocated bandwidth");
3054 teardown_do_callbacks
:
3055 /* From here on reallocation is unnecessary */
3056 cec_curr
->realloc_valid
= B_FALSE
;
3057 cec_curr
->realloc_chnl_num
= 0;
3058 cec_curr
->realloc_bandwidth
= 0;
3060 /* Now we are going into the callbacks */
3061 cec_curr
->in_callbacks
= B_TRUE
;
3063 /* Unlock the Isoch CEC member list */
3064 mutex_exit(&cec_curr
->isoch_cec_mutex
);
3066 /* Call all of the teardown_target() callbacks */
3067 member_curr
= cec_curr
->cec_member_list_head
;
3068 while (member_curr
!= NULL
) {
3069 if (member_curr
->isoch_cec_evts
.teardown_target
!= NULL
) {
3071 member_curr
->isoch_cec_evts
.teardown_target
;
3072 teardown_callback(t1394_isoch_cec_hdl
,
3073 member_curr
->isoch_cec_evts_arg
);
3075 member_curr
= member_curr
->cec_mem_next
;
3078 /* Lock the Isoch CEC member list */
3079 mutex_enter(&cec_curr
->isoch_cec_mutex
);
3081 /* We are finished with the callbacks */
3082 cec_curr
->in_callbacks
= B_FALSE
;
3083 if (cec_curr
->cec_want_wakeup
== B_TRUE
) {
3084 cec_curr
->cec_want_wakeup
= B_FALSE
;
3085 cv_broadcast(&cec_curr
->in_callbacks_cv
);
3089 * Now "join" and "setup" are legal state transitions
3090 * and "start" and "teardown" are illegal state transitions
3092 CEC_SET_LEGAL(cec_curr
, (ISOCH_CEC_JOIN
| ISOCH_CEC_SETUP
));
3093 CEC_SET_ILLEGAL(cec_curr
, (ISOCH_CEC_START
| ISOCH_CEC_TEARDOWN
));
3095 /* And if the member list is empty, then "free" is legal too */
3096 if ((cec_curr
->cec_member_list_head
== NULL
) &&
3097 (cec_curr
->cec_member_list_tail
== NULL
)) {
3098 CEC_SET_LEGAL(cec_curr
, ISOCH_CEC_FREE
);
3101 /* Unlock the Isoch CEC member list */
3102 mutex_exit(&cec_curr
->isoch_cec_mutex
);
3103 TNF_PROBE_0_DEBUG(t1394_teardown_isoch_cec_exit
,
3104 S1394_TNF_SL_ISOCH_STACK
, "");
3105 return (DDI_SUCCESS
);
3109 * Function: t1394_alloc_isoch_dma()
3110 * Input(s): t1394_hdl The target "handle" returned by
3112 * idi This structure contains information
3113 * for configuring the data flow for
3115 * flags The flags parameter is unused (for now)
3117 * Output(s): t1394_idma_hdl The IDMA "handle" used in all
3118 * subsequent isoch_dma() calls
3119 * result Used to pass more specific info back
3122 * Description: t1394_alloc_isoch_dma() allocates and initializes an
3123 * isochronous DMA resource for transmitting or receiving
3124 * isochronous data. If it fails, result may hold
3125 * T1394_EIDMA_NO_RESRCS, indicating that no isoch DMA resource
3130 t1394_alloc_isoch_dma(t1394_handle_t t1394_hdl
,
3131 id1394_isoch_dmainfo_t
*idi
, uint_t flags
,
3132 t1394_isoch_dma_handle_t
*t1394_idma_hdl
, int *result
)
3137 TNF_PROBE_0_DEBUG(t1394_alloc_isoch_dma_enter
,
3138 S1394_TNF_SL_ISOCH_STACK
, "");
3140 ASSERT(t1394_hdl
!= NULL
);
3141 ASSERT(idi
!= NULL
);
3142 ASSERT(t1394_idma_hdl
!= NULL
);
3144 /* Find the HAL this target resides on */
3145 hal
= ((s1394_target_t
*)t1394_hdl
)->on_hal
;
3147 /* Sanity check dma options. If talk enabled, listen should be off */
3148 if ((idi
->idma_options
& ID1394_TALK
) &&
3149 (idi
->idma_options
!= ID1394_TALK
)) {
3150 TNF_PROBE_1(t1394_alloc_isoch_dma_talk_conflict_error
,
3151 S1394_TNF_SL_ISOCH_ERROR
, "", tnf_string
, msg
,
3152 "conflicting idma options; talker and listener");
3153 TNF_PROBE_0_DEBUG(t1394_alloc_isoch_dma_exit
,
3154 S1394_TNF_SL_ISOCH_STACK
, "");
3156 *result
= T1394_EIDMA_CONFLICT
;
3157 return (DDI_FAILURE
);
3160 /* Only one listen mode allowed */
3161 if ((idi
->idma_options
& ID1394_LISTEN_PKT_MODE
) &&
3162 (idi
->idma_options
& ID1394_LISTEN_BUF_MODE
)) {
3163 TNF_PROBE_1(t1394_alloc_isoch_dma_listen_conflict_error
,
3164 S1394_TNF_SL_ISOCH_ERROR
, "", tnf_string
, msg
,
3165 "conflicting idma options; both listener modes set");
3166 TNF_PROBE_0_DEBUG(t1394_alloc_isoch_dma_exit
,
3167 S1394_TNF_SL_ISOCH_STACK
, "");
3169 *result
= T1394_EIDMA_CONFLICT
;
3170 return (DDI_FAILURE
);
3173 /* Have HAL alloc a resource and compile ixl */
3174 ret
= HAL_CALL(hal
).alloc_isoch_dma(hal
->halinfo
.hal_private
, idi
,
3175 (void **)t1394_idma_hdl
, result
);
3177 if (ret
!= DDI_SUCCESS
) {
3178 TNF_PROBE_1(t1394_alloc_isoch_dma_hal_error
,
3179 S1394_TNF_SL_ISOCH_ERROR
, "", tnf_string
, msg
,
3180 "HAL alloc_isoch_dma error, maybe IXL compilation");
3181 if (*result
== IXL1394_ENO_DMA_RESRCS
) {
3182 *result
= T1394_EIDMA_NO_RESRCS
;
3186 TNF_PROBE_0_DEBUG(t1394_alloc_isoch_dma_exit
,
3187 S1394_TNF_SL_ISOCH_STACK
, "");
3192 * Function: t1394_free_isoch_dma()
3193 * Input(s): t1394_hdl The target "handle" returned by
3195 * flags The flags parameter is unused (for now)
3196 * t1394_idma_hdl The IDMA "handle" returned by
3197 * t1394_alloc_isoch_dma()
3201 * Description: t1394_free_isoch_dma() is used to free all DMA resources
3202 * allocated for the isoch stream associated with t1394_idma_hdl.
3206 t1394_free_isoch_dma(t1394_handle_t t1394_hdl
, uint_t flags
,
3207 t1394_isoch_dma_handle_t
*t1394_idma_hdl
)
3211 TNF_PROBE_0_DEBUG(t1394_free_isoch_dma_enter
,
3212 S1394_TNF_SL_ISOCH_STACK
, "");
3214 ASSERT(t1394_hdl
!= NULL
);
3215 ASSERT(*t1394_idma_hdl
!= NULL
);
3217 /* Find the HAL this target resides on */
3218 hal
= ((s1394_target_t
*)t1394_hdl
)->on_hal
;
3220 /* Tell HAL to release local isoch dma resources */
3221 HAL_CALL(hal
).free_isoch_dma(hal
->halinfo
.hal_private
, *t1394_idma_hdl
);
3223 /* Null out isoch handle */
3224 *t1394_idma_hdl
= NULL
;
3226 TNF_PROBE_0_DEBUG(t1394_free_isoch_dma_exit
,
3227 S1394_TNF_SL_ISOCH_STACK
, "");
3231 * Function: t1394_start_isoch_dma()
3232 * Input(s): t1394_hdl The target "handle" returned by
3234 * t1394_idma_hdl The IDMA "handle" returned by
3235 * t1394_alloc_isoch_dma()
3236 * idma_ctrlinfo This structure contains control args
3237 * used when starting isoch DMA for
3238 * the allocated resource
3239 * flags One flag defined - ID1394_START_ON_CYCLE
3241 * Output(s): result Used to pass more specific info back
3244 * Description: t1394_start_isoch_dma() is used to start DMA for the isoch
3245 * stream associated with t1394_idma_hdl.
3249 t1394_start_isoch_dma(t1394_handle_t t1394_hdl
,
3250 t1394_isoch_dma_handle_t t1394_idma_hdl
,
3251 id1394_isoch_dma_ctrlinfo_t
*idma_ctrlinfo
, uint_t flags
,
3257 TNF_PROBE_0_DEBUG(t1394_start_isoch_dma_enter
,
3258 S1394_TNF_SL_ISOCH_STACK
, "");
3260 ASSERT(t1394_hdl
!= NULL
);
3261 ASSERT(t1394_idma_hdl
!= NULL
);
3262 ASSERT(idma_ctrlinfo
!= NULL
);
3264 /* Find the HAL this target resides on */
3265 hal
= ((s1394_target_t
*)t1394_hdl
)->on_hal
;
3267 ret
= HAL_CALL(hal
).start_isoch_dma(hal
->halinfo
.hal_private
,
3268 (void *)t1394_idma_hdl
, idma_ctrlinfo
, flags
, result
);
3270 TNF_PROBE_0_DEBUG(t1394_start_isoch_dma_exit
,
3271 S1394_TNF_SL_ISOCH_STACK
, "");
3276 * Function: t1394_stop_isoch_dma()
3277 * Input(s): t1394_hdl The target "handle" returned by
3279 * t1394_idma_hdl The IDMA "handle" returned by
3280 * t1394_alloc_isoch_dma()
3281 * flags The flags parameter is unused (for now)
3285 * Description: t1394_stop_isoch_dma() is used to stop DMA for the isoch
3286 * stream associated with t1394_idma_hdl.
3290 t1394_stop_isoch_dma(t1394_handle_t t1394_hdl
,
3291 t1394_isoch_dma_handle_t t1394_idma_hdl
, uint_t flags
)
3296 TNF_PROBE_0_DEBUG(t1394_stop_isoch_dma_enter
,
3297 S1394_TNF_SL_ISOCH_STACK
, "");
3299 ASSERT(t1394_hdl
!= NULL
);
3300 ASSERT(t1394_idma_hdl
!= NULL
);
3302 /* Find the HAL this target resides on */
3303 hal
= ((s1394_target_t
*)t1394_hdl
)->on_hal
;
3305 HAL_CALL(hal
).stop_isoch_dma(hal
->halinfo
.hal_private
,
3306 (void *)t1394_idma_hdl
, &result
);
3308 TNF_PROBE_0_DEBUG(t1394_stop_isoch_dma_exit
,
3309 S1394_TNF_SL_ISOCH_STACK
, "");
3313 * Function: t1394_update_isoch_dma()
3314 * Input(s): t1394_hdl The target "handle" returned by
3316 * t1394_idma_hdl The IDMA "handle" returned by
3317 * t1394_alloc_isoch_dma()
3318 * idma_updateinfo This structure contains ixl command args
3319 * used when updating args in an
3320 * existing list of ixl commands with
3321 * args in a new list of ixl commands.
3322 * flags The flags parameter is unused (for now)
3324 * Output(s): result Used to pass more specific info back
3327 * Description: t1394_update_isoch_dma() is used to alter an IXL program that
3328 * has already been built (compiled) by t1394_alloc_isoch_dma().
3332 t1394_update_isoch_dma(t1394_handle_t t1394_hdl
,
3333 t1394_isoch_dma_handle_t t1394_idma_hdl
,
3334 id1394_isoch_dma_updateinfo_t
*idma_updateinfo
, uint_t flags
,
3340 TNF_PROBE_0_DEBUG(t1394_update_isoch_dma_enter
,
3341 S1394_TNF_SL_ISOCH_STACK
, "");
3343 ASSERT(t1394_hdl
!= NULL
);
3344 ASSERT(t1394_idma_hdl
!= NULL
);
3345 ASSERT(idma_updateinfo
!= NULL
);
3347 /* Find the HAL this target resides on */
3348 hal
= ((s1394_target_t
*)t1394_hdl
)->on_hal
;
3350 ret
= HAL_CALL(hal
).update_isoch_dma(hal
->halinfo
.hal_private
,
3351 (void *)t1394_idma_hdl
, idma_updateinfo
, flags
, result
);
3353 TNF_PROBE_0_DEBUG(t1394_update_isoch_dma_exit
,
3354 S1394_TNF_SL_ISOCH_STACK
, "");
3359 * Function: t1394_initiate_bus_reset()
3360 * Input(s): t1394_hdl The target "handle" returned by
3362 * flags The flags parameter is unused (for now)
3366 * Description: t1394_initiate_bus_reset() determines whether the local
3367 * device has a P1394A PHY and will support the arbitrated
3368 * short bus reset. If not, it will initiate a normal bus reset.
3372 t1394_initiate_bus_reset(t1394_handle_t t1394_hdl
, uint_t flags
)
3377 TNF_PROBE_0_DEBUG(t1394_initiate_bus_reset_enter
,
3378 S1394_TNF_SL_BR_STACK
, "");
3380 ASSERT(t1394_hdl
!= NULL
);
3382 /* Find the HAL this target resides on */
3383 hal
= ((s1394_target_t
*)t1394_hdl
)->on_hal
;
3386 if (hal
->halinfo
.phy
== H1394_PHY_1394A
) {
3387 ret
= HAL_CALL(hal
).short_bus_reset(hal
->halinfo
.hal_private
);
3388 if (ret
!= DDI_SUCCESS
) {
3389 TNF_PROBE_1(t1394_initiate_bus_reset_error
,
3390 S1394_TNF_SL_ERROR
, "", tnf_string
, msg
,
3391 "Error initiating short bus reset");
3394 ret
= HAL_CALL(hal
).bus_reset(hal
->halinfo
.hal_private
);
3395 if (ret
!= DDI_SUCCESS
) {
3396 TNF_PROBE_1(t1394_initiate_bus_reset_error
,
3397 S1394_TNF_SL_ERROR
, "", tnf_string
, msg
,
3398 "Error initiating bus reset");
3402 TNF_PROBE_0_DEBUG(t1394_initiate_bus_reset_exit
,
3403 S1394_TNF_SL_BR_STACK
, "");
3407 * Function: t1394_get_topology_map()
3408 * Input(s): t1394_hdl The target "handle" returned by
3410 * bus_generation The current generation
3411 * tm_length The size of the tm_buffer given
3412 * flags The flags parameter is unused (for now)
3414 * Output(s): tm_buffer Filled in by the 1394 Software Framework
3415 * with the contents of the local
3418 * Description: t1394_get_topology_map() returns the 1394 TOPLOGY_MAP. See
3419 * IEEE 1394-1995 Section 8.2.3.4.1 for format information. This
3420 * call can fail if there is a generation mismatch or the
3421 * tm_buffer is too small to hold the TOPOLOGY_MAP.
3425 t1394_get_topology_map(t1394_handle_t t1394_hdl
, uint_t bus_generation
,
3426 size_t tm_length
, uint_t flags
, uint32_t *tm_buffer
)
3432 TNF_PROBE_0_DEBUG(t1394_get_topology_map_enter
, S1394_TNF_SL_CSR_STACK
,
3435 ASSERT(t1394_hdl
!= NULL
);
3437 /* Find the HAL this target resides on */
3438 hal
= ((s1394_target_t
*)t1394_hdl
)->on_hal
;
3440 /* Lock the topology tree */
3441 mutex_enter(&hal
->topology_tree_mutex
);
3443 /* Check the bus_generation for the Topology Map */
3444 if (bus_generation
!= hal
->generation_count
) {
3445 /* Unlock the topology tree */
3446 mutex_exit(&hal
->topology_tree_mutex
);
3447 TNF_PROBE_1(t1394_get_topology_map_error
,
3448 S1394_TNF_SL_CSR_ERROR
, "", tnf_string
, msg
,
3449 "Generation mismatch");
3450 TNF_PROBE_0_DEBUG(t1394_get_topology_map_exit
,
3451 S1394_TNF_SL_CSR_STACK
, "");
3452 return (DDI_FAILURE
);
3455 tm_ptr
= (uint32_t *)hal
->CSR_topology_map
;
3456 length
= tm_ptr
[0] >> 16;
3457 length
= length
* 4; /* Bytes instead of quadlets */
3458 length
= length
+ 4; /* don't forget the first quad */
3460 /* Check that the buffer is big enough */
3461 if (length
> (uint_t
)tm_length
) {
3462 /* Unlock the topology tree */
3463 mutex_exit(&hal
->topology_tree_mutex
);
3464 TNF_PROBE_1(t1394_get_topology_map_error
,
3465 S1394_TNF_SL_CSR_ERROR
, "", tnf_string
, msg
,
3466 "Buffer size too small");
3467 TNF_PROBE_0_DEBUG(t1394_get_topology_map_exit
,
3468 S1394_TNF_SL_CSR_STACK
, "");
3469 return (DDI_FAILURE
);
3473 bcopy(tm_ptr
, tm_buffer
, length
);
3475 /* Unlock the topology tree */
3476 mutex_exit(&hal
->topology_tree_mutex
);
3477 TNF_PROBE_0_DEBUG(t1394_get_topology_map_exit
, S1394_TNF_SL_CSR_STACK
,
3479 return (DDI_SUCCESS
);
3483 * Function: t1394_CRC16()
3484 * Input(s): d The data to compute the CRC-16 for
3485 * crc_length The length into the data to compute for
3486 * flags The flags parameter is unused (for now)
3488 * Output(s): CRC The CRC-16 computed for the length
3491 * Description: t1394_CRC16() implements ISO/IEC 13213:1994, ANSI/IEEE Std
3492 * 1212, 1994 - 8.1.5.
3496 t1394_CRC16(uint32_t *d
, size_t crc_length
, uint_t flags
)
3498 /* Implements ISO/IEC 13213:1994, */
3499 /* ANSI/IEEE Std 1212, 1994 - 8.1.5 */
3502 TNF_PROBE_0_DEBUG(t1394_CRC16_enter
, S1394_TNF_SL_STACK
, "");
3504 ret
= s1394_CRC16((uint_t
*)d
, (uint_t
)crc_length
);
3506 TNF_PROBE_0_DEBUG(t1394_CRC16_exit
, S1394_TNF_SL_STACK
, "");
3511 * Function: t1394_add_cfgrom_entry()
3512 * Input(s): t1394_hdl The target "handle" returned by
3514 * cfgrom_entryinfo This structure holds the cfgrom key,
3516 * flags The flags parameter is unused (for now)
3518 * Output(s): t1394_cfgrom_hdl The ConfigROM "handle" used in
3519 * t1394_rem_cfgrom_entry()
3520 * result Used to pass more specific info back
3523 * Description: t1394_add_cfgrom_entry() adds an entry to the local Config ROM,
3524 * updating the directory entries as necessary. This call could
3525 * fail because there is no room for the new entry in Config ROM
3526 * (T1394_ECFGROM_FULL), the key is invalid (T1394_EINVALID_PARAM),
3527 * or it was called in interrupt context (T1394_EINVALID_CONTEXT).
3531 t1394_add_cfgrom_entry(t1394_handle_t t1394_hdl
,
3532 t1394_cfgrom_entryinfo_t
*cfgrom_entryinfo
, uint_t flags
,
3533 t1394_cfgrom_handle_t
*t1394_cfgrom_hdl
, int *result
)
3536 s1394_target_t
*target
;
3542 TNF_PROBE_0_DEBUG(t1394_add_cfgrom_entry_enter
,
3543 S1394_TNF_SL_CFGROM_STACK
, "");
3545 ASSERT(t1394_hdl
!= NULL
);
3547 target
= (s1394_target_t
*)t1394_hdl
;
3549 key
= cfgrom_entryinfo
->ce_key
;
3550 buffer
= cfgrom_entryinfo
->ce_buffer
;
3551 size
= (uint_t
)cfgrom_entryinfo
->ce_size
;
3553 /* Check for a valid size */
3555 *result
= T1394_EINVALID_PARAM
;
3556 TNF_PROBE_1_DEBUG(t1394_add_cfgrom_entry_error
,
3557 S1394_TNF_SL_CFGROM_ERROR
, "", tnf_string
, msg
,
3558 "Invalid size of Config ROM buffer (== 0)");
3559 TNF_PROBE_0_DEBUG(t1394_add_cfgrom_entry_exit
,
3560 S1394_TNF_SL_CFGROM_STACK
, "");
3561 return (DDI_FAILURE
);
3564 /* Check for a valid key type */
3565 if (((key
<< IEEE1212_KEY_VALUE_SHIFT
) & IEEE1212_KEY_TYPE_MASK
) == 0) {
3566 *result
= T1394_EINVALID_PARAM
;
3567 TNF_PROBE_1_DEBUG(t1394_add_cfgrom_entry_error
,
3568 S1394_TNF_SL_CFGROM_ERROR
, "", tnf_string
, msg
,
3569 "Invalid key_type in Config ROM key");
3570 TNF_PROBE_0_DEBUG(t1394_add_cfgrom_entry_exit
,
3571 S1394_TNF_SL_CFGROM_STACK
, "");
3572 return (DDI_FAILURE
);
3575 /* Find the HAL this target resides on */
3576 hal
= target
->on_hal
;
3578 /* Is this on the interrupt stack? */
3579 if (servicing_interrupt()) {
3580 *result
= T1394_EINVALID_CONTEXT
;
3581 TNF_PROBE_0_DEBUG(t1394_add_cfgrom_entry_exit
,
3582 S1394_TNF_SL_CFGROM_STACK
, "");
3583 return (DDI_FAILURE
);
3586 /* Lock the Config ROM buffer */
3587 mutex_enter(&hal
->local_config_rom_mutex
);
3589 ret
= s1394_add_config_rom_entry(hal
, key
, buffer
, size
,
3590 (void **)t1394_cfgrom_hdl
, result
);
3591 if (ret
!= DDI_SUCCESS
) {
3592 if (*result
== CMD1394_ERSRC_CONFLICT
)
3593 *result
= T1394_ECFGROM_FULL
;
3594 mutex_exit(&hal
->local_config_rom_mutex
);
3596 TNF_PROBE_1(t1394_add_cfgrom_entry_error
,
3597 S1394_TNF_SL_CFGROM_ERROR
, "", tnf_string
, msg
,
3598 "Failed in s1394_add_cfgrom_entry()");
3599 TNF_PROBE_0_DEBUG(t1394_add_cfgrom_entry_exit
,
3600 "stacktrace 1394 s1394", "");
3604 /* Setup the timeout function */
3605 if (hal
->config_rom_timer_set
== B_FALSE
) {
3606 hal
->config_rom_timer_set
= B_TRUE
;
3607 mutex_exit(&hal
->local_config_rom_mutex
);
3608 hal
->config_rom_timer
=
3609 timeout(s1394_update_config_rom_callback
, hal
,
3610 drv_usectohz(CONFIG_ROM_UPDATE_DELAY
* 1000));
3612 mutex_exit(&hal
->local_config_rom_mutex
);
3615 TNF_PROBE_0_DEBUG(t1394_add_cfgrom_entry_exit
,
3616 S1394_TNF_SL_CFGROM_STACK
, "");
3621 * Function: t1394_rem_cfgrom_entry()
3622 * Input(s): t1394_hdl The target "handle" returned by
3624 * flags The flags parameter is unused (for now)
3625 * t1394_cfgrom_hdl The ConfigROM "handle" returned by
3626 * t1394_add_cfgrom_entry()
3628 * Output(s): result Used to pass more specific info back
3631 * Description: t1394_rem_cfgrom_entry() is used to remove a previously added
3632 * Config ROM entry (indicated by t1394_cfgrom_hdl).
3636 t1394_rem_cfgrom_entry(t1394_handle_t t1394_hdl
, uint_t flags
,
3637 t1394_cfgrom_handle_t
*t1394_cfgrom_hdl
, int *result
)
3640 s1394_target_t
*target
;
3643 TNF_PROBE_0_DEBUG(t1394_rem_cfgrom_entry_enter
,
3644 S1394_TNF_SL_CFGROM_STACK
, "");
3646 ASSERT(t1394_hdl
!= NULL
);
3648 target
= (s1394_target_t
*)t1394_hdl
;
3650 /* Find the HAL this target resides on */
3651 hal
= target
->on_hal
;
3653 /* Is this on the interrupt stack? */
3654 if (servicing_interrupt()) {
3655 *result
= T1394_EINVALID_CONTEXT
;
3656 TNF_PROBE_0_DEBUG(t1394_rem_cfgrom_entry_exit
,
3657 S1394_TNF_SL_CFGROM_STACK
, "");
3658 return (DDI_FAILURE
);
3661 /* Lock the Config ROM buffer */
3662 mutex_enter(&hal
->local_config_rom_mutex
);
3664 ret
= s1394_remove_config_rom_entry(hal
, (void **)t1394_cfgrom_hdl
,
3666 if (ret
!= DDI_SUCCESS
) {
3667 mutex_exit(&hal
->local_config_rom_mutex
);
3668 TNF_PROBE_1(t1394_rem_cfgrom_entry_error
,
3669 S1394_TNF_SL_CFGROM_ERROR
, "", tnf_string
, msg
,
3670 "Failed in s1394_remove_cfgrom_entry()");
3671 TNF_PROBE_0_DEBUG(t1394_rem_cfgrom_entry_exit
,
3672 "stacktrace 1394 s1394", "");
3676 /* Setup the timeout function */
3677 if (hal
->config_rom_timer_set
== B_FALSE
) {
3678 hal
->config_rom_timer_set
= B_TRUE
;
3679 mutex_exit(&hal
->local_config_rom_mutex
);
3680 hal
->config_rom_timer
=
3681 timeout(s1394_update_config_rom_callback
, hal
,
3682 drv_usectohz(CONFIG_ROM_UPDATE_DELAY
* 1000));
3684 mutex_exit(&hal
->local_config_rom_mutex
);
3687 TNF_PROBE_0_DEBUG(t1394_rem_cfgrom_entry_exit
,
3688 S1394_TNF_SL_CFGROM_STACK
, "");
3693 * Function: t1394_get_targetinfo()
3694 * Input(s): t1394_hdl The target "handle" returned by
3696 * bus_generation The current generation
3697 * flags The flags parameter is unused (for now)
3699 * Output(s): targetinfo Structure containing max_payload,
3700 * max_speed, and target node ID.
3702 * Description: t1394_get_targetinfo() is used to retrieve information specific
3703 * to a target device. It will fail if the generation given
3704 * does not match the current generation.
3708 t1394_get_targetinfo(t1394_handle_t t1394_hdl
, uint_t bus_generation
,
3709 uint_t flags
, t1394_targetinfo_t
*targetinfo
)
3712 s1394_target_t
*target
;
3718 TNF_PROBE_0_DEBUG(t1394_get_targetinfo_enter
, S1394_TNF_SL_STACK
, "");
3720 ASSERT(t1394_hdl
!= NULL
);
3722 /* Find the HAL this target resides on */
3723 hal
= ((s1394_target_t
*)t1394_hdl
)->on_hal
;
3725 target
= (s1394_target_t
*)t1394_hdl
;
3727 /* Lock the topology tree */
3728 mutex_enter(&hal
->topology_tree_mutex
);
3730 /* Check the bus_generation */
3731 if (bus_generation
!= hal
->generation_count
) {
3732 /* Unlock the topology tree */
3733 mutex_exit(&hal
->topology_tree_mutex
);
3734 TNF_PROBE_3(t1394_get_targetinfo_error
, S1394_TNF_SL_STACK
, "",
3735 tnf_string
, msg
, "Generation mismatch",
3736 tnf_uint
, gen
, bus_generation
,
3737 tnf_uint
, current_gen
, hal
->generation_count
);
3738 return (DDI_FAILURE
);
3741 rw_enter(&hal
->target_list_rwlock
, RW_READER
);
3743 * If there is no node, report T1394_INVALID_NODEID for target_nodeID;
3744 * current_max_speed and current_max_payload are undefined for this
3747 if (((target
->target_state
& S1394_TARG_GONE
) != 0) ||
3748 (target
->on_node
== NULL
)) {
3749 targetinfo
->target_nodeID
= T1394_INVALID_NODEID
;
3750 TNF_PROBE_1_DEBUG(t1394_get_targetinfo_exit
,
3751 S1394_TNF_SL_STACK
, "", tnf_string
, msg
, "No device");
3753 targetinfo
->target_nodeID
=
3754 (target
->on_hal
->node_id
& IEEE1394_BUS_NUM_MASK
) |
3755 target
->on_node
->node_num
;
3757 from_node
= (target
->on_hal
->node_id
) & IEEE1394_NODE_NUM_MASK
;
3758 to_node
= target
->on_node
->node_num
;
3760 targetinfo
->current_max_speed
= (uint_t
)s1394_speed_map_get(
3761 hal
, from_node
, to_node
);
3763 /* Get current_max_payload */
3764 s1394_get_maxpayload(target
, &dev
, &curr
);
3765 targetinfo
->current_max_payload
= curr
;
3767 TNF_PROBE_3_DEBUG(t1394_get_targetinfo_exit
,
3768 S1394_TNF_SL_STACK
, "",
3769 tnf_uint
, payload
, targetinfo
->current_max_payload
,
3770 tnf_uint
, speed
, targetinfo
->current_max_speed
,
3771 tnf_uint
, nodeid
, targetinfo
->target_nodeID
);
3774 rw_exit(&hal
->target_list_rwlock
);
3775 /* Unlock the topology tree */
3776 mutex_exit(&hal
->topology_tree_mutex
);
3777 return (DDI_SUCCESS
);