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