5255 uts shouldn't open-code ISP2
[illumos-gate.git] / usr / src / uts / common / io / 1394 / t1394.c
blob4cc56bac296b946e08df1f9794404f0b3857f745
1 /*
2 * CDDL HEADER START
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
19 * CDDL HEADER END
22 * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
27 * t1394.c
28 * 1394 Target Driver Interface
29 * This file contains all of the 1394 Software Framework routines called
30 * by target drivers
33 #include <sys/sysmacros.h>
34 #include <sys/conf.h>
35 #include <sys/ddi.h>
36 #include <sys/sunddi.h>
37 #include <sys/types.h>
38 #include <sys/kmem.h>
39 #include <sys/disp.h>
40 #include <sys/tnf_probe.h>
42 #include <sys/1394/t1394.h>
43 #include <sys/1394/s1394.h>
44 #include <sys/1394/h1394.h>
45 #include <sys/1394/ieee1394.h>
47 static int s1394_allow_detach = 0;
50 * Function: t1394_attach()
51 * Input(s): dip The dip given to the target driver
52 * in it's attach() routine
53 * version The version of the target driver -
54 * T1394_VERSION_V1
55 * flags The flags parameter is unused (for now)
57 * Output(s): attachinfo Used to pass info back to target,
58 * including bus generation, local
59 * node ID, dma attribute, etc.
60 * t1394_hdl The target "handle" to be used for
61 * all subsequent calls into the
62 * 1394 Software Framework
64 * Description: t1394_attach() registers the target (based on its dip) with
65 * the 1394 Software Framework. It returns the bus_generation,
66 * local_nodeID, iblock_cookie and other useful information to
67 * the target, as well as a handle (t1394_hdl) that will be used
68 * in all subsequent calls into this framework.
70 /* ARGSUSED */
71 int
72 t1394_attach(dev_info_t *dip, int version, uint_t flags,
73 t1394_attachinfo_t *attachinfo, t1394_handle_t *t1394_hdl)
75 s1394_hal_t *hal;
76 s1394_target_t *target;
77 uint_t dev;
78 uint_t curr;
79 uint_t unit_dir;
80 int hp_node = 0;
82 ASSERT(t1394_hdl != NULL);
83 ASSERT(attachinfo != NULL);
85 TNF_PROBE_0_DEBUG(t1394_attach_enter, S1394_TNF_SL_HOTPLUG_STACK, "");
87 *t1394_hdl = NULL;
89 if (version != T1394_VERSION_V1) {
90 TNF_PROBE_1(t1394_attach_error, S1394_TNF_SL_HOTPLUG_ERROR, "",
91 tnf_string, msg, "Invalid version");
92 TNF_PROBE_0_DEBUG(t1394_attach_exit,
93 S1394_TNF_SL_HOTPLUG_STACK, "");
94 return (DDI_FAILURE);
97 hal = s1394_dip_to_hal(ddi_get_parent(dip));
98 if (hal == NULL) {
99 TNF_PROBE_1(t1394_attach_error, S1394_TNF_SL_HOTPLUG_ERROR, "",
100 tnf_string, msg, "No parent dip found for target");
101 TNF_PROBE_0_DEBUG(t1394_attach_exit,
102 S1394_TNF_SL_HOTPLUG_STACK, "");
103 return (DDI_FAILURE);
106 ASSERT(MUTEX_NOT_HELD(&hal->topology_tree_mutex));
108 hp_node = ddi_prop_exists(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS,
109 "hp-node");
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);
126 if (hp_node != 0) {
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,
139 "on_node == NULL");
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;
181 } else {
182 target->on_hal->target_tail->target_next = target;
183 target->target_prev = target->on_hal->target_tail;
184 target->on_hal->target_tail = target;
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
200 * t1394_attach()
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.
210 /* ARGSUSED */
212 t1394_detach(t1394_handle_t *t1394_hdl, uint_t flags)
214 s1394_target_t *target;
215 uint_t num_cmds;
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;
231 if (num_cmds != 0) {
232 rw_exit(&target->on_hal->target_list_rwlock);
233 mutex_exit(&target->on_hal->topology_tree_mutex);
234 TNF_PROBE_1(t1394_detach_error, S1394_TNF_SL_HOTPLUG_ERROR, "",
235 tnf_string, msg, "Must free all commands before detach()");
236 TNF_PROBE_0_DEBUG(t1394_detach_exit,
237 S1394_TNF_SL_HOTPLUG_STACK, "");
238 return (DDI_FAILURE);
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;
249 } else {
250 if (target->target_prev)
251 target->target_prev->target_next = target->target_next;
252 if (target->target_next)
253 target->target_next->target_prev = target->target_prev;
254 if (target->on_hal->target_head == target)
255 target->on_hal->target_head = target->target_next;
256 if (target->on_hal->target_tail == target)
257 target->on_hal->target_tail = target->target_prev;
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);
265 /* Free memory */
266 kmem_free(target, sizeof (s1394_target_t));
268 *t1394_hdl = NULL;
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
277 * t1394_attach()
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)
294 s1394_hal_t *hal;
295 s1394_target_t *target;
296 s1394_cmd_priv_t *s_priv;
297 uint_t num_cmds;
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
359 * t1394_attach()
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.
371 /* ARGSUSED */
373 t1394_free_cmd(t1394_handle_t t1394_hdl, uint_t flags, cmd1394_cmd_t **cmdp)
375 s1394_hal_t *hal;
376 s1394_target_t *target;
377 s1394_cmd_priv_t *s_priv;
378 uint_t num_cmds;
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;
394 if (num_cmds == 0) {
395 rw_exit(&hal->target_list_rwlock);
396 TNF_PROBE_2(t1394_free_cmd_error, S1394_TNF_SL_ATREQ_ERROR, "",
397 tnf_string, msg, "No commands left to be freed "
398 "(num_cmds <= 0)", tnf_uint, num_cmds, num_cmds);
399 TNF_PROBE_0_DEBUG(t1394_free_cmd_exit,
400 S1394_TNF_SL_ATREQ_STACK, "");
401 ASSERT(num_cmds != 0);
402 return (DDI_FAILURE);
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 */
433 *cmdp = NULL;
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
445 * t1394_attach()
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
452 * onto the 1394 bus.
455 t1394_read(t1394_handle_t t1394_hdl, cmd1394_cmd_t *cmd)
457 s1394_hal_t *to_hal;
458 s1394_target_t *target;
459 s1394_cmd_priv_t *s_priv;
460 s1394_hal_state_t state;
461 int ret;
462 int err;
464 TNF_PROBE_0_DEBUG(t1394_read_enter, S1394_TNF_SL_ATREQ_STACK, "");
466 ASSERT(t1394_hdl != NULL);
467 ASSERT(cmd != 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,
477 "");
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 "
507 "intr context");
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 "
556 "context");
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;
584 } else {
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);
600 } else {
601 /* Block (if necessary) */
602 goto block_on_asynch_cmd;
605 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
616 * t1394_attach()
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
623 * onto the 1394 bus.
626 t1394_write(t1394_handle_t t1394_hdl, cmd1394_cmd_t *cmd)
628 s1394_hal_t *to_hal;
629 s1394_target_t *target;
630 s1394_cmd_priv_t *s_priv;
631 s1394_hal_state_t state;
632 int ret;
633 int err;
635 TNF_PROBE_0_DEBUG(t1394_write_enter, S1394_TNF_SL_ATREQ_STACK, "");
637 ASSERT(t1394_hdl != NULL);
638 ASSERT(cmd != 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,
648 "");
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,
680 "");
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 "
691 "context");
692 TNF_PROBE_0_DEBUG(t1394_write_exit, S1394_TNF_SL_ATREQ_STACK,
693 "");
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,
721 "");
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,
756 "");
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);
777 } else {
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);
794 } else {
795 /* Block (if necessary) */
796 s1394_block_on_asynch_cmd(cmd);
798 TNF_PROBE_0_DEBUG(t1394_write_exit, S1394_TNF_SL_ATREQ_STACK,
799 "");
800 return (DDI_SUCCESS);
805 * Function: t1394_lock()
806 * Input(s): t1394_hdl The target "handle" returned by
807 * t1394_attach()
808 * cmd Pointer to the command to send
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
814 * onto the 1394 bus.
817 t1394_lock(t1394_handle_t t1394_hdl, cmd1394_cmd_t *cmd)
819 s1394_hal_t *to_hal;
820 s1394_target_t *target;
821 s1394_cmd_priv_t *s_priv;
822 s1394_hal_state_t state;
823 cmd1394_lock_type_t lock_type;
824 uint_t num_retries;
825 int ret;
827 TNF_PROBE_0_DEBUG(t1394_lock_enter, S1394_TNF_SL_ATREQ_STACK, "");
829 ASSERT(t1394_hdl != NULL);
830 ASSERT(cmd != 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,
840 "");
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 "
868 "t1394_lock()");
869 TNF_PROBE_0_DEBUG(t1394_lock_exit, S1394_TNF_SL_ATREQ_STACK,
870 "");
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 "
883 "context");
884 TNF_PROBE_0_DEBUG(t1394_lock_exit, S1394_TNF_SL_ATREQ_STACK,
885 "");
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);
900 switch (lock_type) {
901 case CMD1394_LOCK_MASK_SWAP:
902 case CMD1394_LOCK_FETCH_ADD:
903 case CMD1394_LOCK_LITTLE_ADD:
904 case CMD1394_LOCK_BOUNDED_ADD:
905 case CMD1394_LOCK_WRAP_ADD:
906 case CMD1394_LOCK_COMPARE_SWAP:
907 ret = s1394_compare_swap(to_hal, target, cmd);
908 break;
910 case CMD1394_LOCK_BIT_AND:
911 case CMD1394_LOCK_BIT_OR:
912 case CMD1394_LOCK_BIT_XOR:
913 case CMD1394_LOCK_INCREMENT:
914 case CMD1394_LOCK_DECREMENT:
915 case CMD1394_LOCK_ADD:
916 case CMD1394_LOCK_SUBTRACT:
917 case CMD1394_LOCK_THRESH_ADD:
918 case CMD1394_LOCK_THRESH_SUBTRACT:
919 case CMD1394_LOCK_CLIP_ADD:
920 case CMD1394_LOCK_CLIP_SUBTRACT:
921 ret = s1394_split_lock_req(to_hal, target, cmd);
922 break;
924 default:
925 TNF_PROBE_1(t1394_lock_error, S1394_TNF_SL_ATREQ_ERROR, "",
926 tnf_string, msg, "Invalid lock_type in command");
927 cmd->cmd_result = CMD1394_EINVALID_COMMAND;
928 ret = DDI_FAILURE;
929 break;
932 TNF_PROBE_0_DEBUG(t1394_lock_exit, S1394_TNF_SL_ATREQ_STACK, "");
933 return (ret);
937 * Function: t1394_alloc_addr()
938 * Input(s): t1394_hdl The target "handle" returned by
939 * t1394_attach()
940 * addr_allocp The structure used to specify the type,
941 * size, permissions, and callbacks
942 * (if any) for the requested block
943 * of 1394 address space
944 * flags The flags parameter is unused (for now)
946 * Output(s): result Used to pass more specific info back
947 * to target
949 * Description: t1394_alloc_addr() requests that part of the 1394 Address Space
950 * on the local node be set aside for this target driver, and
951 * associated with this address space should be some permissions
952 * and callbacks. If the request is unable to be fulfilled,
953 * t1394_alloc_addr() will return DDI_FAILURE and result will
954 * indicate the reason. T1394_EINVALID_PARAM indicates that the
955 * combination of flags given is invalid, and T1394_EALLOC_ADDR
956 * indicates that the requested type of address space is
957 * unavailable.
959 /* ARGSUSED */
961 t1394_alloc_addr(t1394_handle_t t1394_hdl, t1394_alloc_addr_t *addr_allocp,
962 uint_t flags, int *result)
964 s1394_hal_t *hal;
965 s1394_target_t *target;
966 uint64_t addr_lo;
967 uint64_t addr_hi;
968 int err;
970 TNF_PROBE_0_DEBUG(t1394_alloc_addr_enter, S1394_TNF_SL_ARREQ_STACK,
971 "");
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,
1001 "Invalid flags "
1002 "(RDs on, notify off, no backing store)");
1003 TNF_PROBE_0_DEBUG(t1394_alloc_addr_exit,
1004 S1394_TNF_SL_ARREQ_STACK, "");
1006 /* kstats - addr alloc failures */
1007 hal->hal_kstats->addr_alloc_fail++;
1008 return (DDI_FAILURE);
1009 } else {
1010 addr_allocp->aa_enable &= ~T1394_ADDR_RDENBL;
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,
1029 "Invalid flags "
1030 "(WRs on, notify off, no backing store)");
1031 TNF_PROBE_0_DEBUG(t1394_alloc_addr_exit,
1032 S1394_TNF_SL_ARREQ_STACK, "");
1034 /* kstats - addr alloc failures */
1035 hal->hal_kstats->addr_alloc_fail++;
1036 return (DDI_FAILURE);
1037 } else {
1038 addr_allocp->aa_enable &= ~T1394_ADDR_WRENBL;
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,
1057 "Invalid flags "
1058 "(LKs on, notify off, no backing store)");
1059 TNF_PROBE_0_DEBUG(t1394_alloc_addr_exit,
1060 S1394_TNF_SL_ARREQ_STACK, "");
1062 /* kstats - addr alloc failures */
1063 hal->hal_kstats->addr_alloc_fail++;
1064 return (DDI_FAILURE);
1065 } else {
1066 addr_allocp->aa_enable &= ~T1394_ADDR_LKENBL;
1070 /* If not T1394_ADDR_FIXED, then allocate a block */
1071 if (addr_allocp->aa_type != T1394_ADDR_FIXED) {
1072 err = s1394_request_addr_blk((s1394_hal_t *)target->on_hal,
1073 addr_allocp);
1074 if (err != DDI_SUCCESS) {
1075 *result = T1394_EALLOC_ADDR;
1076 /* kstats - addr alloc failures */
1077 hal->hal_kstats->addr_alloc_fail++;
1078 } else {
1079 *result = T1394_NOERROR;
1081 TNF_PROBE_0_DEBUG(t1394_alloc_addr_exit,
1082 S1394_TNF_SL_ARREQ_STACK, "");
1083 return (err);
1084 } else {
1085 err = s1394_claim_addr_blk((s1394_hal_t *)target->on_hal,
1086 addr_allocp);
1087 if (err != DDI_SUCCESS) {
1088 *result = T1394_EALLOC_ADDR;
1089 /* kstats - addr alloc failures */
1090 hal->hal_kstats->addr_alloc_fail++;
1091 } else {
1092 *result = T1394_NOERROR;
1093 /* If physical, update the AR request counter */
1094 if ((addr_lo >= hal->physical_addr_lo) &&
1095 (addr_hi <= hal->physical_addr_hi)) {
1096 rw_enter(&hal->target_list_rwlock, RW_WRITER);
1097 target->physical_arreq_enabled++;
1098 rw_exit(&hal->target_list_rwlock);
1100 s1394_physical_arreq_set_one(target);
1103 TNF_PROBE_0_DEBUG(t1394_alloc_addr_exit,
1104 S1394_TNF_SL_ARREQ_STACK, "");
1105 return (err);
1110 * Function: t1394_free_addr()
1111 * Input(s): t1394_hdl The target "handle" returned by
1112 * t1394_attach()
1113 * addr_hdl The address "handle" returned by the
1114 * the t1394_alloc_addr() routine
1115 * flags The flags parameter is unused (for now)
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().
1123 /* ARGSUSED */
1125 t1394_free_addr(t1394_handle_t t1394_hdl, t1394_addr_handle_t *addr_hdl,
1126 uint_t flags)
1128 s1394_addr_space_blk_t *curr_blk;
1129 s1394_hal_t *hal;
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);
1156 *addr_hdl = NULL;
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
1168 * t1394_attach()
1169 * resp Pointer to the command which the
1170 * target received in it's callback
1171 * flags The flags parameter is unused (for now)
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.
1186 /* ARGSUSED */
1188 t1394_recv_request_done(t1394_handle_t t1394_hdl, cmd1394_cmd_t *resp,
1189 uint_t flags)
1191 s1394_hal_t *hal;
1192 s1394_cmd_priv_t *s_priv;
1193 h1394_cmd_priv_t *h_priv;
1194 mblk_t *curr_blk;
1195 size_t msgb_len;
1196 size_t size;
1197 int ret;
1198 boolean_t response = B_TRUE;
1199 boolean_t posted_write = B_FALSE;
1200 boolean_t write_cmd = B_FALSE;
1201 boolean_t mblk_too_small;
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)) {
1226 write_cmd = B_TRUE;
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)))
1234 response = B_FALSE;
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,
1244 h_priv);
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;
1259 msgb_len = 0;
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
1270 * to the HAL
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) {
1279 msgb_len +=
1280 (curr_blk->b_wptr - curr_blk->b_rptr);
1282 if (msgb_len >= size) {
1283 mblk_too_small = B_FALSE;
1284 break;
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
1297 * to the HAL
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);
1305 /* FALLTHROUGH */
1306 case IEEE1394_RESP_CONFLICT_ERROR:
1307 case IEEE1394_RESP_DATA_ERROR:
1308 case IEEE1394_RESP_TYPE_ERROR:
1309 case IEEE1394_RESP_ADDRESS_ERROR:
1310 ret = s1394_send_response(hal, resp);
1311 TNF_PROBE_0_DEBUG(t1394_recv_request_done_exit,
1312 S1394_TNF_SL_ARREQ_STACK, "");
1313 return (ret);
1315 default:
1316 TNF_PROBE_1(t1394_recv_request_done_error,
1317 S1394_TNF_SL_ARREQ_ERROR, "", tnf_string, msg,
1318 "Invalid response code");
1319 TNF_PROBE_0_DEBUG(t1394_recv_request_done_exit,
1320 S1394_TNF_SL_ARREQ_STACK, "");
1321 return (DDI_FAILURE);
1327 * Function: t1394_fcp_register_controller()
1328 * Input(s): t1394_hdl The target "handle" returned by
1329 * t1394_attach()
1330 * evts The structure in which the target
1331 * specifies its callback routines
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
1340 * controller.
1342 /* ARGSUSED */
1344 t1394_fcp_register_controller(t1394_handle_t t1394_hdl, t1394_fcp_evts_t *evts,
1345 uint_t flags)
1347 int result;
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, "");
1358 return (result);
1362 * Function: t1394_fcp_unregister_controller()
1363 * Input(s): t1394_hdl The target "handle" returned by
1364 * t1394_attach()
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
1371 * controller.
1374 t1394_fcp_unregister_controller(t1394_handle_t t1394_hdl)
1376 int result;
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, "");
1387 return (result);
1391 * Function: t1394_fcp_register_target()
1392 * Input(s): t1394_hdl The target "handle" returned by
1393 * t1394_attach()
1394 * evts The structure in which the target
1395 * specifies its callback routines
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
1404 * target.
1406 /* ARGSUSED */
1408 t1394_fcp_register_target(t1394_handle_t t1394_hdl, t1394_fcp_evts_t *evts,
1409 uint_t flags)
1411 int result;
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, "");
1422 return (result);
1426 * Function: t1394_fcp_unregister_target()
1427 * Input(s): t1394_hdl The target "handle" returned by
1428 * t1394_attach()
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
1435 * target.
1438 t1394_fcp_unregister_target(t1394_handle_t t1394_hdl)
1440 int result;
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, "");
1451 return (result);
1455 * Function: t1394_cmp_register()
1456 * Input(s): t1394_hdl The target "handle" returned by
1457 * t1394_attach()
1458 * evts The structure in which the target
1459 * specifies its callback routines
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
1466 * device.
1468 /* ARGSUSED */
1470 t1394_cmp_register(t1394_handle_t t1394_hdl, t1394_cmp_evts_t *evts,
1471 uint_t flags)
1473 int result;
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, "");
1482 return (result);
1486 * Function: t1394_cmp_unregister()
1487 * Input(s): t1394_hdl The target "handle" returned by
1488 * t1394_attach()
1489 * evts The structure in which the target
1490 * specifies its callback routines
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
1497 * device.
1500 t1394_cmp_unregister(t1394_handle_t t1394_hdl)
1502 int result;
1504 TNF_PROBE_0_DEBUG(t1394_cmp_unregister_enter, S1394_TNF_SL_CMP_STACK,
1505 "");
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,
1512 "");
1513 return (result);
1517 * Function: t1394_cmp_read()
1518 * Input(s): t1394_hdl The target "handle" returned by
1519 * t1394_attach()
1520 * reg Register type.
1521 * valp Returned register value.
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)
1532 int result;
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, "");
1541 return (result);
1545 * Function: t1394_cmp_cas()
1546 * Input(s): t1394_hdl The target "handle" returned by
1547 * t1394_attach()
1548 * reg Register type.
1549 * arg_val Compare argument.
1550 * new_val New register value.
1551 * old_valp Returned original register value.
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)
1563 int result;
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,
1570 new_val, old_valp);
1572 TNF_PROBE_0_DEBUG(t1394_cmp_read_exit, S1394_TNF_SL_CMP_STACK, "");
1573 return (result);
1577 * Function: t1394_alloc_isoch_single()
1578 * Input(s): t1394_hdl The target "handle" returned by
1579 * t1394_attach()
1580 * sii The structure used to set up the
1581 * overall characteristics of the
1582 * isochronous stream
1583 * flags The flags parameter is unused (for now)
1585 * Output(s): setup_args Contains the channel number that was
1586 * allocated
1587 * t1394_single_hdl This in the isoch "handle" used in
1588 * t1394_free_isoch_single()
1589 * result Used to pass more specific info back
1590 * to target
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.
1599 /* ARGSUSED */
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)
1606 s1394_hal_t *hal;
1607 s1394_isoch_cec_t *cec_new;
1608 t1394_join_isochinfo_t jii;
1609 int ret;
1610 int err;
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 |
1679 ISOCH_CEC_SETUP;
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()");
1719 ASSERT(0);
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()");
1741 *result = err;
1743 /* Leave the Isoch CEC */
1744 ret = t1394_leave_isoch_cec(t1394_hdl,
1745 (t1394_isoch_cec_handle_t)cec_new, 0);
1746 if (ret != DDI_SUCCESS) {
1747 /* Unable to leave the Isoch CEC */
1748 TNF_PROBE_1(t1394_alloc_isoch_single_error,
1749 S1394_TNF_SL_ISOCH_ERROR, "", tnf_string, msg,
1750 "Unexpected error from t1394_leave_isoch_cec()");
1751 ASSERT(0);
1754 /* Free up the Isoch CEC */
1755 ret = t1394_free_isoch_cec(t1394_hdl, flags,
1756 (t1394_isoch_cec_handle_t *)&cec_new);
1757 if (ret != DDI_SUCCESS) {
1758 /* Unable to free the Isoch CEC */
1759 TNF_PROBE_1(t1394_alloc_isoch_single_error,
1760 S1394_TNF_SL_ISOCH_ERROR, "", tnf_string, msg,
1761 "Unexpected error from t1394_free_isoch_cec()");
1762 ASSERT(0);
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
1789 * t1394_attach()
1790 * t1394_single_hdl The isoch "handle" return by
1791 * t1394_alloc_isoch_single()
1792 * flags The flags parameter is unused (for now)
1794 * Output(s): None
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().
1800 /* ARGSUSED */
1801 void
1802 t1394_free_isoch_single(t1394_handle_t t1394_hdl,
1803 t1394_isoch_single_handle_t *t1394_single_hdl, uint_t flags)
1805 s1394_isoch_cec_t *cec_curr;
1806 int ret;
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()");
1827 ASSERT(0);
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()");
1840 ASSERT(0);
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()");
1853 ASSERT(0);
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
1866 * t1394_attach()
1867 * props The structure used to set up the
1868 * overall characteristics of for
1869 * the Isoch CEC.
1870 * flags The flags parameter is unused (for now)
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
1879 /* ARGSUSED */
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)
1884 s1394_hal_t *hal;
1885 s1394_isoch_cec_t *cec_new;
1886 uint64_t temp;
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 */
1911 if (!ISP2(temp)) {
1912 TNF_PROBE_1(t1394_alloc_isoch_cec_error,
1913 S1394_TNF_SL_ISOCH_ERROR, "", tnf_string, msg,
1914 "Invalid channel mask");
1915 TNF_PROBE_0_DEBUG(t1394_alloc_isoch_cec_exit,
1916 S1394_TNF_SL_ISOCH_STACK, "");
1917 return (DDI_FAILURE);
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 |
1966 ISOCH_CEC_SETUP;
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
1986 * t1394_attach()
1987 * flags The flags parameter is unused (for now)
1988 * t1394_isoch_cec_hdl The Isoch CEC "handle" returned by
1989 * t1394_alloc_isoch_cec()
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.
1998 /* ARGSUSED */
2000 t1394_free_isoch_cec(t1394_handle_t t1394_hdl, uint_t flags,
2001 t1394_isoch_cec_handle_t *t1394_isoch_cec_hdl)
2003 s1394_hal_t *hal;
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
2070 * t1394_attach()
2071 * t1394_isoch_cec_hdl The Isoch CEC "handle" returned by
2072 * t1394_alloc_isoch_cec()
2073 * flags The flags parameter is unused (for now)
2074 * join_isoch_info This structure provides infomation
2075 * about a target that wishes to join
2076 * the given Isoch CEC. It gives
2077 * max_speed, channel_mask, etc.
2079 * Output(s): DDI_SUCCESS Target successfully joined the
2080 * Isoch CEC
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.
2089 /* ARGSUSED */
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)
2095 s1394_hal_t *hal;
2096 s1394_isoch_cec_t *cec_curr;
2097 s1394_isoch_cec_member_t *member_new;
2098 uint64_t check_mask;
2099 uint_t curr_max_speed;
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;
2167 } else {
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
2239 * t1394_attach()
2240 * t1394_isoch_cec_hdl The Isoch CEC "handle" returned by
2241 * t1394_alloc_isoch_cec()
2242 * flags The flags parameter is unused (for now)
2244 * Output(s): DDI_SUCCESS Target successfully left the
2245 * Isoch CEC
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.
2254 /* ARGSUSED */
2256 t1394_leave_isoch_cec(t1394_handle_t t1394_hdl,
2257 t1394_isoch_cec_handle_t t1394_isoch_cec_hdl, uint_t flags)
2259 s1394_hal_t *hal;
2260 s1394_isoch_cec_t *cec_curr;
2261 s1394_isoch_cec_member_t *member_curr;
2262 s1394_isoch_cec_member_t *member_temp;
2263 boolean_t found;
2264 uint64_t temp_channel_mask;
2265 uint_t temp_max_speed;
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 */
2301 found = B_FALSE;
2302 temp_channel_mask = cec_curr->cec_alloc_props.cec_channel_mask;
2303 temp_max_speed = cec_curr->cec_alloc_props.cec_max_speed;
2304 member_curr = cec_curr->cec_member_list_head;
2305 while (member_curr != NULL) {
2306 if (member_curr->cec_mem_target ==
2307 (s1394_target_t *)t1394_hdl) {
2308 member_temp = member_curr;
2309 found = B_TRUE;
2310 } else {
2311 /* Keep track of channel mask and max speed info */
2312 temp_channel_mask &= member_curr->req_channel_mask;
2313 if (member_curr->req_max_speed < temp_max_speed)
2314 temp_max_speed = member_curr->req_max_speed;
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);
2329 } else {
2330 /* This member's departure may change filter constraints */
2331 cec_curr->filter_current_speed = temp_max_speed;
2332 cec_curr->filter_channel_mask = temp_channel_mask;
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
2369 * t1394_attach()
2370 * t1394_isoch_cec_hdl The Isoch CEC "handle" returned by
2371 * t1394_alloc_isoch_cec()
2372 * flags The flags parameter is unused (for now)
2374 * Output(s): result Used to pass more specific info back
2375 * to target
2377 * Description: t1394_setup_isoch_cec() directs the 1394 Software Framework
2378 * to allocate isochronous resources and invoke the setup_target()
2379 * callback for each member of the Isoch CEC. This call may
2380 * fail because bandwidth was unavailable (T1394_ENO_BANDWIDTH),
2381 * channels were unavailable (T1394_ENO_CHANNEL), or one of the
2382 * member targets returned failure from its setup_target()
2383 * callback.
2385 /* ARGSUSED */
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)
2390 s1394_hal_t *hal;
2391 s1394_isoch_cec_t *cec_curr;
2392 s1394_isoch_cec_member_t *member_curr;
2393 t1394_setup_target_args_t target_args;
2394 uint64_t temp_chnl_mask;
2395 uint32_t old_chnl;
2396 uint32_t try_chnl;
2397 uint_t bw_alloc_units;
2398 uint_t generation;
2399 int chnl_num;
2400 int err;
2401 int ret;
2402 int j;
2403 int (*setup_callback)(t1394_isoch_cec_handle_t, opaque_t,
2404 t1394_setup_target_args_t *);
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)
2464 continue;
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,
2471 &err);
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 */
2480 } else {
2481 *result = T1394_ENO_BANDWIDTH;
2482 /* Unlock the Isoch CEC member list */
2483 mutex_exit(&cec_curr->isoch_cec_mutex);
2484 TNF_PROBE_1(t1394_setup_isoch_cec_error,
2485 S1394_TNF_SL_ISOCH_ERROR, "", tnf_string,
2486 msg, "Unable to allocate isoch bandwidth");
2487 TNF_PROBE_0_DEBUG(t1394_setup_isoch_cec_exit,
2488 S1394_TNF_SL_ISOCH_STACK, "");
2489 return (DDI_FAILURE);
2493 /* Check that the generation has not changed - */
2494 /* don't need the lock (read only) */
2495 if (generation != hal->generation_count)
2496 continue;
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,
2524 &err);
2525 } else {
2526 ret = s1394_channel_alloc(hal,
2527 try_chnl, generation,
2528 S1394_CHANNEL_ALLOC_LO, &old_chnl,
2529 &err);
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))
2537 break;
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)
2554 continue;
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,
2561 generation, &err);
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) {
2568 continue;
2569 } else {
2570 TNF_PROBE_1(t1394_setup_isoch_cec_error,
2571 S1394_TNF_SL_ISOCH_ERROR, "",
2572 tnf_string, msg,
2573 "Unable to free isoch bandwidth");
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)
2589 break;
2590 else if (err == CMD1394_EBUSRESET)
2591 continue;
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;
2612 setup_do_callbacks:
2613 /* Call all of the setup_target() callbacks */
2614 target_args.channel_num = chnl_num;
2615 target_args.channel_speed = cec_curr->filter_current_speed;
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;
2624 *result = 0;
2625 while (member_curr != NULL) {
2626 if (member_curr->isoch_cec_evts.setup_target != NULL) {
2627 setup_callback =
2628 member_curr->isoch_cec_evts.setup_target;
2629 ret = setup_callback(t1394_isoch_cec_hdl,
2630 member_curr->isoch_cec_evts_arg, &target_args);
2631 if (ret != DDI_SUCCESS)
2632 *result = T1394_ETARGET;
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 |
2653 ISOCH_CEC_SETUP));
2655 /* Unlock the Isoch CEC member list */
2656 mutex_exit(&cec_curr->isoch_cec_mutex);
2658 /* Return DDI_FAILURE if any targets failed setup */
2659 if (*result != 0) {
2660 TNF_PROBE_1(t1394_setup_isoch_cec_error,
2661 S1394_TNF_SL_ISOCH_ERROR, "", tnf_string, msg,
2662 "Target returned error in setup_target()");
2663 TNF_PROBE_0_DEBUG(t1394_setup_isoch_cec_exit,
2664 S1394_TNF_SL_ISOCH_STACK, "");
2665 return (DDI_FAILURE);
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
2676 * t1394_attach()
2677 * t1394_isoch_cec_hdl The Isoch CEC "handle" returned by
2678 * t1394_alloc_isoch_cec()
2679 * flags The flags parameter is unused (for now)
2681 * Output(s): DDI_SUCCESS All start_target() callbacks returned
2682 * successfully
2683 * DDI_FAILURE One or more start_target() callbacks
2684 * returned failure
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.
2690 /* ARGSUSED */
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;
2697 int ret;
2698 boolean_t err;
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;
2749 err = B_FALSE;
2750 while (member_curr != NULL) {
2751 if (member_curr->isoch_cec_evts.start_target != NULL) {
2752 start_callback =
2753 member_curr->isoch_cec_evts.start_target;
2754 ret = start_callback(t1394_isoch_cec_hdl,
2755 member_curr->isoch_cec_evts_arg);
2756 if (ret != DDI_SUCCESS)
2757 err = B_TRUE;
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
2800 * t1394_attach()
2801 * t1394_isoch_cec_hdl The Isoch CEC "handle" returned by
2802 * t1394_alloc_isoch_cec()
2803 * flags The flags parameter is unused (for now)
2805 * Output(s): DDI_SUCCESS Target successfully stopped the
2806 * Isoch CEC
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()
2814 * call, etc.)
2816 /* ARGSUSED */
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) {
2875 stop_callback =
2876 member_curr->isoch_cec_evts.stop_target;
2877 stop_callback(t1394_isoch_cec_hdl,
2878 member_curr->isoch_cec_evts_arg);
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
2911 * t1394_attach()
2912 * t1394_isoch_cec_hdl The Isoch CEC "handle" returned by
2913 * t1394_alloc_isoch_cec()
2914 * flags The flags parameter is unused (for now)
2916 * Output(s): DDI_SUCCESS Target successfully tore down the
2917 * Isoch CEC
2918 * DDI_FAILURE Target failed to tear down the
2919 * Isoch CEC
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.
2928 /* ARGSUSED */
2930 t1394_teardown_isoch_cec(t1394_handle_t t1394_hdl,
2931 t1394_isoch_cec_handle_t t1394_isoch_cec_hdl, uint_t flags)
2933 s1394_hal_t *hal;
2934 s1394_isoch_cec_t *cec_curr;
2935 s1394_isoch_cec_member_t *member_curr;
2936 uint32_t chnl_mask;
2937 uint32_t old_chnl_mask;
2938 uint_t bw_alloc_units;
2939 uint_t generation;
2940 int ret;
2941 int err;
2942 void (*teardown_callback)(t1394_isoch_cec_handle_t, opaque_t);
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;
3022 } else {
3023 TNF_PROBE_1(t1394_teardown_isoch_cec_error,
3024 S1394_TNF_SL_ISOCH_ERROR, "", tnf_string, msg,
3025 "Unable to free allocated bandwidth");
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);
3037 } else {
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;
3047 } else {
3048 TNF_PROBE_1(t1394_teardown_isoch_cec_error,
3049 S1394_TNF_SL_ISOCH_ERROR, "", tnf_string, msg,
3050 "Unable to free allocated bandwidth");
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) {
3070 teardown_callback =
3071 member_curr->isoch_cec_evts.teardown_target;
3072 teardown_callback(t1394_isoch_cec_hdl,
3073 member_curr->isoch_cec_evts_arg);
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
3111 * t1394_attach()
3112 * idi This structure contains information
3113 * for configuring the data flow for
3114 * isochronous DMA
3115 * flags The flags parameter is unused (for now)
3117 * Output(s): t1394_idma_hdl The IDMA "handle" used in all
3118 * subsequent isoch_dma() calls
3119 * result Used to pass more specific info back
3120 * to target
3122 * Description: t1394_alloc_isoch_dma() allocates and initializes an
3123 * isochronous DMA resource for transmitting or receiving
3124 * isochronous data. If it fails, result may hold
3125 * T1394_EIDMA_NO_RESRCS, indicating that no isoch DMA resource
3126 * are available.
3128 /* ARGSUSED */
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)
3134 s1394_hal_t *hal;
3135 int ret;
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, "");
3188 return (ret);
3192 * Function: t1394_free_isoch_dma()
3193 * Input(s): t1394_hdl The target "handle" returned by
3194 * t1394_attach()
3195 * flags The flags parameter is unused (for now)
3196 * t1394_idma_hdl The IDMA "handle" returned by
3197 * t1394_alloc_isoch_dma()
3199 * Output(s): None
3201 * Description: t1394_free_isoch_dma() is used to free all DMA resources
3202 * allocated for the isoch stream associated with t1394_idma_hdl.
3204 /* ARGSUSED */
3205 void
3206 t1394_free_isoch_dma(t1394_handle_t t1394_hdl, uint_t flags,
3207 t1394_isoch_dma_handle_t *t1394_idma_hdl)
3209 s1394_hal_t *hal;
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
3233 * t1394_attach()
3234 * t1394_idma_hdl The IDMA "handle" returned by
3235 * t1394_alloc_isoch_dma()
3236 * idma_ctrlinfo This structure contains control args
3237 * used when starting isoch DMA for
3238 * the allocated resource
3239 * flags One flag defined - ID1394_START_ON_CYCLE
3241 * Output(s): result Used to pass more specific info back
3242 * to target
3244 * Description: t1394_start_isoch_dma() is used to start DMA for the isoch
3245 * stream associated with t1394_idma_hdl.
3247 /* ARGSUSED */
3249 t1394_start_isoch_dma(t1394_handle_t t1394_hdl,
3250 t1394_isoch_dma_handle_t t1394_idma_hdl,
3251 id1394_isoch_dma_ctrlinfo_t *idma_ctrlinfo, uint_t flags,
3252 int *result)
3254 s1394_hal_t *hal;
3255 int ret;
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, "");
3272 return (ret);
3276 * Function: t1394_stop_isoch_dma()
3277 * Input(s): t1394_hdl The target "handle" returned by
3278 * t1394_attach()
3279 * t1394_idma_hdl The IDMA "handle" returned by
3280 * t1394_alloc_isoch_dma()
3281 * flags The flags parameter is unused (for now)
3283 * Output(s): None
3285 * Description: t1394_stop_isoch_dma() is used to stop DMA for the isoch
3286 * stream associated with t1394_idma_hdl.
3288 /* ARGSUSED */
3289 void
3290 t1394_stop_isoch_dma(t1394_handle_t t1394_hdl,
3291 t1394_isoch_dma_handle_t t1394_idma_hdl, uint_t flags)
3293 s1394_hal_t *hal;
3294 int result;
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
3315 * t1394_attach()
3316 * t1394_idma_hdl The IDMA "handle" returned by
3317 * t1394_alloc_isoch_dma()
3318 * idma_updateinfo This structure contains ixl command args
3319 * used when updating args in an
3320 * existing list of ixl commands with
3321 * args in a new list of ixl commands.
3322 * flags The flags parameter is unused (for now)
3324 * Output(s): result Used to pass more specific info back
3325 * to target
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().
3330 /* ARGSUSED */
3332 t1394_update_isoch_dma(t1394_handle_t t1394_hdl,
3333 t1394_isoch_dma_handle_t t1394_idma_hdl,
3334 id1394_isoch_dma_updateinfo_t *idma_updateinfo, uint_t flags,
3335 int *result)
3337 s1394_hal_t *hal;
3338 int ret;
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, "");
3355 return (ret);
3359 * Function: t1394_initiate_bus_reset()
3360 * Input(s): t1394_hdl The target "handle" returned by
3361 * t1394_attach()
3362 * flags The flags parameter is unused (for now)
3364 * Output(s): None
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.
3370 /* ARGSUSED */
3371 void
3372 t1394_initiate_bus_reset(t1394_handle_t t1394_hdl, uint_t flags)
3374 s1394_hal_t *hal;
3375 int ret;
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;
3385 /* Reset the bus */
3386 if (hal->halinfo.phy == H1394_PHY_1394A) {
3387 ret = HAL_CALL(hal).short_bus_reset(hal->halinfo.hal_private);
3388 if (ret != DDI_SUCCESS) {
3389 TNF_PROBE_1(t1394_initiate_bus_reset_error,
3390 S1394_TNF_SL_ERROR, "", tnf_string, msg,
3391 "Error initiating short bus reset");
3393 } else {
3394 ret = HAL_CALL(hal).bus_reset(hal->halinfo.hal_private);
3395 if (ret != DDI_SUCCESS) {
3396 TNF_PROBE_1(t1394_initiate_bus_reset_error,
3397 S1394_TNF_SL_ERROR, "", tnf_string, msg,
3398 "Error initiating bus reset");
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
3409 * t1394_attach()
3410 * bus_generation The current generation
3411 * tm_length The size of the tm_buffer given
3412 * flags The flags parameter is unused (for now)
3414 * Output(s): tm_buffer Filled in by the 1394 Software Framework
3415 * with the contents of the local
3416 * TOPOLOGY_MAP
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.
3423 /* ARGSUSED */
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)
3428 s1394_hal_t *hal;
3429 uint32_t *tm_ptr;
3430 uint_t length;
3432 TNF_PROBE_0_DEBUG(t1394_get_topology_map_enter, S1394_TNF_SL_CSR_STACK,
3433 "");
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);
3472 /* Do the copy */
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,
3478 "");
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
3489 * of data specified
3491 * Description: t1394_CRC16() implements ISO/IEC 13213:1994, ANSI/IEEE Std
3492 * 1212, 1994 - 8.1.5.
3494 /* ARGSUSED */
3495 uint_t
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 */
3500 uint_t ret;
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, "");
3507 return (ret);
3511 * Function: t1394_add_cfgrom_entry()
3512 * Input(s): t1394_hdl The target "handle" returned by
3513 * t1394_attach()
3514 * cfgrom_entryinfo This structure holds the cfgrom key,
3515 * buffer, and size
3516 * flags The flags parameter is unused (for now)
3518 * Output(s): t1394_cfgrom_hdl The ConfigROM "handle" used in
3519 * t1394_rem_cfgrom_entry()
3520 * result Used to pass more specific info back
3521 * to target
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).
3529 /* ARGSUSED */
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)
3535 s1394_hal_t *hal;
3536 s1394_target_t *target;
3537 int ret;
3538 uint_t key;
3539 uint_t size;
3540 uint32_t *buffer;
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 */
3554 if (size == 0) {
3555 *result = T1394_EINVALID_PARAM;
3556 TNF_PROBE_1_DEBUG(t1394_add_cfgrom_entry_error,
3557 S1394_TNF_SL_CFGROM_ERROR, "", tnf_string, msg,
3558 "Invalid size of Config ROM buffer (== 0)");
3559 TNF_PROBE_0_DEBUG(t1394_add_cfgrom_entry_exit,
3560 S1394_TNF_SL_CFGROM_STACK, "");
3561 return (DDI_FAILURE);
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", "");
3601 return (ret);
3604 /* Setup the timeout function */
3605 if (hal->config_rom_timer_set == B_FALSE) {
3606 hal->config_rom_timer_set = B_TRUE;
3607 mutex_exit(&hal->local_config_rom_mutex);
3608 hal->config_rom_timer =
3609 timeout(s1394_update_config_rom_callback, hal,
3610 drv_usectohz(CONFIG_ROM_UPDATE_DELAY * 1000));
3611 } else {
3612 mutex_exit(&hal->local_config_rom_mutex);
3615 TNF_PROBE_0_DEBUG(t1394_add_cfgrom_entry_exit,
3616 S1394_TNF_SL_CFGROM_STACK, "");
3617 return (ret);
3621 * Function: t1394_rem_cfgrom_entry()
3622 * Input(s): t1394_hdl The target "handle" returned by
3623 * t1394_attach()
3624 * flags The flags parameter is unused (for now)
3625 * t1394_cfgrom_hdl The ConfigROM "handle" returned by
3626 * t1394_add_cfgrom_entry()
3628 * Output(s): result Used to pass more specific info back
3629 * to target
3631 * Description: t1394_rem_cfgrom_entry() is used to remove a previously added
3632 * Config ROM entry (indicated by t1394_cfgrom_hdl).
3634 /* ARGSUSED */
3636 t1394_rem_cfgrom_entry(t1394_handle_t t1394_hdl, uint_t flags,
3637 t1394_cfgrom_handle_t *t1394_cfgrom_hdl, int *result)
3639 s1394_hal_t *hal;
3640 s1394_target_t *target;
3641 int ret;
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,
3665 result);
3666 if (ret != DDI_SUCCESS) {
3667 mutex_exit(&hal->local_config_rom_mutex);
3668 TNF_PROBE_1(t1394_rem_cfgrom_entry_error,
3669 S1394_TNF_SL_CFGROM_ERROR, "", tnf_string, msg,
3670 "Failed in s1394_remove_cfgrom_entry()");
3671 TNF_PROBE_0_DEBUG(t1394_rem_cfgrom_entry_exit,
3672 "stacktrace 1394 s1394", "");
3673 return (ret);
3676 /* Setup the timeout function */
3677 if (hal->config_rom_timer_set == B_FALSE) {
3678 hal->config_rom_timer_set = B_TRUE;
3679 mutex_exit(&hal->local_config_rom_mutex);
3680 hal->config_rom_timer =
3681 timeout(s1394_update_config_rom_callback, hal,
3682 drv_usectohz(CONFIG_ROM_UPDATE_DELAY * 1000));
3683 } else {
3684 mutex_exit(&hal->local_config_rom_mutex);
3687 TNF_PROBE_0_DEBUG(t1394_rem_cfgrom_entry_exit,
3688 S1394_TNF_SL_CFGROM_STACK, "");
3689 return (ret);
3693 * Function: t1394_get_targetinfo()
3694 * Input(s): t1394_hdl The target "handle" returned by
3695 * t1394_attach()
3696 * bus_generation The current generation
3697 * flags The flags parameter is unused (for now)
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.
3706 /* ARGSUSED */
3708 t1394_get_targetinfo(t1394_handle_t t1394_hdl, uint_t bus_generation,
3709 uint_t flags, t1394_targetinfo_t *targetinfo)
3711 s1394_hal_t *hal;
3712 s1394_target_t *target;
3713 uint_t dev;
3714 uint_t curr;
3715 uint_t from_node;
3716 uint_t to_node;
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
3745 * case.
3747 if (((target->target_state & S1394_TARG_GONE) != 0) ||
3748 (target->on_node == NULL)) {
3749 targetinfo->target_nodeID = T1394_INVALID_NODEID;
3750 TNF_PROBE_1_DEBUG(t1394_get_targetinfo_exit,
3751 S1394_TNF_SL_STACK, "", tnf_string, msg, "No device");
3752 } else {
3753 targetinfo->target_nodeID =
3754 (target->on_hal->node_id & IEEE1394_BUS_NUM_MASK) |
3755 target->on_node->node_num;
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);