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 kmem_free(member_new, sizeof (s1394_isoch_cec_member_t));
1848 /* Unlock the Isoch CEC member list */
1849 mutex_exit(&cec_curr->isoch_cec_mutex);
1850 return (DDI_FAILURE);
1851 }
1852
1853 /* Copy the events information into the struct */
1854 member_new->isoch_cec_evts = join_isoch_info->isoch_cec_evts;
1855 member_new->isoch_cec_evts_arg = join_isoch_info->isoch_cec_evts_arg;
1856 member_new->cec_mem_options = join_isoch_info->jii_options;
1857 member_new->cec_mem_target = (s1394_target_t *)t1394_hdl;
1858
1859 /* Insert new member into Isoch CEC's member list */
1860 s1394_isoch_cec_member_list_insert(hal, cec_curr, member_new);
1861
1862 /* Update the channel mask filter */
1863 cec_curr->filter_channel_mask = check_mask;
1864
1865 /* Update the speed filter */
1866 cec_curr->filter_current_speed = curr_max_speed;
1867
1868 /* Update the talker pointer (if necessary) */
1869 if (join_isoch_info->jii_options & T1394_TALKER)
1870 cec_curr->cec_member_talker = cec_curr->cec_member_list_head;
1871
1872 /*
1873 * Now "leave" is a legal state transition
1874 * and "free" is an illegal state transition
1875 */
1876 CEC_SET_LEGAL(cec_curr, ISOCH_CEC_LEAVE);
1877 CEC_SET_ILLEGAL(cec_curr, ISOCH_CEC_FREE);
1878
1879 /* Unlock the Isoch CEC member list */
1880 mutex_exit(&cec_curr->isoch_cec_mutex);
1881
1882 return (DDI_SUCCESS);
1883 }
1884
1885 /*
1886 * Function: t1394_leave_isoch_cec()
1887 * Input(s): t1394_hdl The target "handle" returned by
1888 * t1394_attach()
1889 * t1394_isoch_cec_hdl The Isoch CEC "handle" returned by
1890 * t1394_alloc_isoch_cec()
1891 * flags The flags parameter is unused (for now)
1892 *
1893 * Output(s): DDI_SUCCESS Target successfully left the
1894 * Isoch CEC
1895 * DDI_FAILURE Target failed to leave the Isoch CEC
1896 *
1897 * Description: t1394_leave_isoch_cec() is used by a target driver to remove
1898 * itself from the Isoch CEC's member list. It is possible
1899 * for this call to fail because the target is not found in
1900 * the current member list, or because it is not an appropriate
1901 * time for a target to leave.
1902 */
1903 /* ARGSUSED */
1904 int
t1394_leave_isoch_cec(t1394_handle_t t1394_hdl,t1394_isoch_cec_handle_t t1394_isoch_cec_hdl,uint_t flags)1905 t1394_leave_isoch_cec(t1394_handle_t t1394_hdl,
1906 t1394_isoch_cec_handle_t t1394_isoch_cec_hdl, uint_t flags)
1907 {
1908 s1394_hal_t *hal;
1909 s1394_isoch_cec_t *cec_curr;
1910 s1394_isoch_cec_member_t *member_curr;
1911 s1394_isoch_cec_member_t *member_temp;
1912 boolean_t found;
1913 uint64_t temp_channel_mask;
1914 uint_t temp_max_speed;
1915
1916 ASSERT(t1394_hdl != NULL);
1917 ASSERT(t1394_isoch_cec_hdl != NULL);
1918
1919 hal = ((s1394_target_t *)t1394_hdl)->on_hal;
1920
1921 /* Convert the handle to an Isoch CEC pointer */
1922 cec_curr = (s1394_isoch_cec_t *)t1394_isoch_cec_hdl;
1923
1924 /* Lock the Isoch CEC member list */
1925 mutex_enter(&cec_curr->isoch_cec_mutex);
1926
1927 /* Are we in any callbacks? (Wait for them to finish) */
1928 while (CEC_IN_ANY_CALLBACKS(cec_curr)) {
1929 cec_curr->cec_want_wakeup = B_TRUE;
1930 cv_wait(&cec_curr->in_callbacks_cv,
1931 &cec_curr->isoch_cec_mutex);
1932 }
1933
1934 /* Is "leave" a legal state transition? */
1935 if (CEC_TRANSITION_LEGAL(cec_curr, ISOCH_CEC_LEAVE) == 0) {
1936 /* Unlock the Isoch CEC member list */
1937 mutex_exit(&cec_curr->isoch_cec_mutex);
1938 return (DDI_FAILURE);
1939 }
1940
1941 /* Find the Target on the CEC's member list */
1942 found = B_FALSE;
1943 temp_channel_mask = cec_curr->cec_alloc_props.cec_channel_mask;
1944 temp_max_speed = cec_curr->cec_alloc_props.cec_max_speed;
1945 member_curr = cec_curr->cec_member_list_head;
1946 while (member_curr != NULL) {
1947 if (member_curr->cec_mem_target ==
1948 (s1394_target_t *)t1394_hdl) {
1949 member_temp = member_curr;
1950 found = B_TRUE;
1951 } else {
1952 /* Keep track of channel mask and max speed info */
1953 temp_channel_mask &= member_curr->req_channel_mask;
1954 if (member_curr->req_max_speed < temp_max_speed)
1955 temp_max_speed = member_curr->req_max_speed;
1956 }
1957 member_curr = member_curr->cec_mem_next;
1958 }
1959
1960 /* Target not found on this Isoch CEC */
1961 if (found == B_FALSE) {
1962 /* Unlock the Isoch CEC member list */
1963 mutex_exit(&cec_curr->isoch_cec_mutex);
1964 return (DDI_FAILURE);
1965 } else {
1966 /* This member's departure may change filter constraints */
1967 cec_curr->filter_current_speed = temp_max_speed;
1968 cec_curr->filter_channel_mask = temp_channel_mask;
1969 }
1970
1971 /* Remove member from Isoch CEC's member list */
1972 s1394_isoch_cec_member_list_remove(hal, cec_curr, member_temp);
1973
1974 /* If we are removing the talker, then update the pointer */
1975 if (cec_curr->cec_member_talker == member_temp)
1976 cec_curr->cec_member_talker = NULL;
1977
1978 /* Is the Isoch CEC's member list empty? */
1979 if ((cec_curr->cec_member_list_head == NULL) &&
1980 (cec_curr->cec_member_list_tail == NULL)) {
1981 /*
1982 * Now "free" _might_ be a legal state transition
1983 * if we aren't in setup or start phases and "leave"
1984 * is definitely an illegal state transition
1985 */
1986 if (CEC_TRANSITION_LEGAL(cec_curr, ISOCH_CEC_JOIN) != 0)
1987 CEC_SET_LEGAL(cec_curr, ISOCH_CEC_FREE);
1988 CEC_SET_ILLEGAL(cec_curr, ISOCH_CEC_LEAVE);
1989 }
1990
1991 /* Unlock the Isoch CEC member list */
1992 mutex_exit(&cec_curr->isoch_cec_mutex);
1993
1994 /* Free the Isoch CEC member structure */
1995 kmem_free(member_temp, sizeof (s1394_isoch_cec_member_t));
1996
1997 return (DDI_SUCCESS);
1998 }
1999
2000 /*
2001 * Function: t1394_setup_isoch_cec()
2002 * Input(s): t1394_hdl The target "handle" returned by
2003 * t1394_attach()
2004 * t1394_isoch_cec_hdl The Isoch CEC "handle" returned by
2005 * t1394_alloc_isoch_cec()
2006 * flags The flags parameter is unused (for now)
2007 *
2008 * Output(s): result Used to pass more specific info back
2009 * to target
2010 *
2011 * Description: t1394_setup_isoch_cec() directs the 1394 Software Framework
2012 * to allocate isochronous resources and invoke the setup_target()
2013 * callback for each member of the Isoch CEC. This call may
2014 * fail because bandwidth was unavailable (T1394_ENO_BANDWIDTH),
2015 * channels were unavailable (T1394_ENO_CHANNEL), or one of the
2016 * member targets returned failure from its setup_target()
2017 * callback.
2018 */
2019 /* ARGSUSED */
2020 int
t1394_setup_isoch_cec(t1394_handle_t t1394_hdl,t1394_isoch_cec_handle_t t1394_isoch_cec_hdl,uint_t flags,int * result)2021 t1394_setup_isoch_cec(t1394_handle_t t1394_hdl,
2022 t1394_isoch_cec_handle_t t1394_isoch_cec_hdl, uint_t flags, int *result)
2023 {
2024 s1394_hal_t *hal;
2025 s1394_isoch_cec_t *cec_curr;
2026 s1394_isoch_cec_member_t *member_curr;
2027 t1394_setup_target_args_t target_args;
2028 uint64_t temp_chnl_mask;
2029 uint32_t old_chnl;
2030 uint32_t try_chnl;
2031 uint_t bw_alloc_units;
2032 uint_t generation;
2033 int chnl_num;
2034 int err;
2035 int ret;
2036 int j;
2037 int (*setup_callback)(t1394_isoch_cec_handle_t, opaque_t,
2038 t1394_setup_target_args_t *);
2039
2040 ASSERT(t1394_hdl != NULL);
2041 ASSERT(t1394_isoch_cec_hdl != NULL);
2042
2043 hal = ((s1394_target_t *)t1394_hdl)->on_hal;
2044
2045 /* Convert the handle to an Isoch CEC pointer */
2046 cec_curr = (s1394_isoch_cec_t *)t1394_isoch_cec_hdl;
2047
2048 /* Lock the Isoch CEC member list */
2049 mutex_enter(&cec_curr->isoch_cec_mutex);
2050
2051 /* Are we in any callbacks? */
2052 if (CEC_IN_ANY_CALLBACKS(cec_curr)) {
2053 /* Unlock the Isoch CEC member list */
2054 mutex_exit(&cec_curr->isoch_cec_mutex);
2055 return (DDI_FAILURE);
2056 }
2057
2058 /* Is "setup" a legal state transition? */
2059 if (CEC_TRANSITION_LEGAL(cec_curr, ISOCH_CEC_SETUP) == 0) {
2060 /* Unlock the Isoch CEC member list */
2061 mutex_exit(&cec_curr->isoch_cec_mutex);
2062 return (DDI_FAILURE);
2063 }
2064
2065 /* If T1394_NO_IRM_ALLOC is set then don't allocate... do callbacks */
2066 if (cec_curr->cec_options & T1394_NO_IRM_ALLOC) {
2067 goto setup_do_callbacks;
2068 }
2069
2070 /* Allocate bandwidth and channels */
2071 for (j = 0; j < S1394_ISOCH_ALLOC_RETRIES; j++) {
2072 /*
2073 * Get the current generation number - don't
2074 * need the lock because we are read only here
2075 */
2076 generation = hal->generation_count;
2077
2078 /* Compute how much bandwidth is needed */
2079 bw_alloc_units = s1394_compute_bw_alloc_units(hal,
2080 cec_curr->bandwidth, cec_curr->filter_current_speed);
2081
2082 /* Check that the generation has not changed - */
2083 /* don't need the lock (read only) */
2084 if (generation != hal->generation_count)
2085 continue;
2086
2087 /* Unlock the Isoch CEC member list */
2088 mutex_exit(&cec_curr->isoch_cec_mutex);
2089
2090 /* Try to allocate the bandwidth */
2091 ret = s1394_bandwidth_alloc(hal, bw_alloc_units, generation,
2092 &err);
2093
2094 /* Lock the Isoch CEC member list */
2095 mutex_enter(&cec_curr->isoch_cec_mutex);
2096
2097 /* If there was a bus reset, start over */
2098 if (ret == DDI_FAILURE) {
2099 if (err == CMD1394_EBUSRESET) {
2100 continue; /* start over and try again */
2101 } else {
2102 *result = T1394_ENO_BANDWIDTH;
2103 /* Unlock the Isoch CEC member list */
2104 mutex_exit(&cec_curr->isoch_cec_mutex);
2105 return (DDI_FAILURE);
2106 }
2107 }
2108
2109 /* Check that the generation has not changed - */
2110 /* don't need the lock (read only) */
2111 if (generation != hal->generation_count)
2112 continue;
2113
2114 /*
2115 * Allocate a channel
2116 * From IEEE 1394-1995, Section 8.3.2.3.8: "Bits
2117 * allocated in the CHANNELS_AVAILABLE_HI field of
2118 * this register shall start at bit zero (channel
2119 * number zero), and additional channel numbers shall
2120 * be represented in a monotonically increasing sequence
2121 * of bit numbers up to a maximum of bit 31 (channel
2122 * number 31). Bits allocated in the CHANNELS_AVAILABLE_LO
2123 * field of this register shall start at bit zero
2124 * (channel number 32), and additional channel numbers
2125 * shall be represented in a monotonically increasing
2126 * sequence of bit numbers up to a maximum of bit 31
2127 * (channel number 63).
2128 */
2129 temp_chnl_mask = cec_curr->filter_channel_mask;
2130 for (chnl_num = 63; chnl_num >= 0; chnl_num--) {
2131 if ((temp_chnl_mask & 1) == 1) {
2132 try_chnl = (1 << ((63 - chnl_num) % 32));
2133
2134 /* Unlock the Isoch CEC member list */
2135 mutex_exit(&cec_curr->isoch_cec_mutex);
2136 if (chnl_num < 32) {
2137 ret = s1394_channel_alloc(hal,
2138 try_chnl, generation,
2139 S1394_CHANNEL_ALLOC_HI, &old_chnl,
2140 &err);
2141 } else {
2142 ret = s1394_channel_alloc(hal,
2143 try_chnl, generation,
2144 S1394_CHANNEL_ALLOC_LO, &old_chnl,
2145 &err);
2146 }
2147 /* Lock the Isoch CEC member list */
2148 mutex_enter(&cec_curr->isoch_cec_mutex);
2149
2150 /* Did we get a channel? (or a bus reset) */
2151 if ((ret == DDI_SUCCESS) ||
2152 (err == CMD1394_EBUSRESET))
2153 break;
2154 }
2155 temp_chnl_mask = temp_chnl_mask >> 1;
2156 }
2157
2158 /* If we've tried all the possible channels, then fail */
2159 if (chnl_num == 0) {
2160 *result = T1394_ENO_CHANNEL;
2161 /*
2162 * If we successfully allocate bandwidth, and
2163 * then fail getting a channel, we need to
2164 * free up the bandwidth
2165 */
2166
2167 /* Check that the generation has not changed */
2168 /* lock not needed here (read only) */
2169 if (generation != hal->generation_count)
2170 continue;
2171
2172 /* Unlock the Isoch CEC member list */
2173 mutex_exit(&cec_curr->isoch_cec_mutex);
2174
2175 /* Try to free up the bandwidth */
2176 ret = s1394_bandwidth_free(hal, bw_alloc_units,
2177 generation, &err);
2178
2179 /* Lock the Isoch CEC member list */
2180 mutex_enter(&cec_curr->isoch_cec_mutex);
2181
2182 if (ret == DDI_FAILURE) {
2183 if (err == CMD1394_EBUSRESET) {
2184 continue;
2185 }
2186 }
2187
2188 /* Unlock the Isoch CEC member list */
2189 mutex_exit(&cec_curr->isoch_cec_mutex);
2190 return (DDI_FAILURE);
2191 }
2192
2193 /* If we got a channel, we're done (else start over) */
2194 if (ret == DDI_SUCCESS)
2195 break;
2196 else if (err == CMD1394_EBUSRESET)
2197 continue;
2198 }
2199
2200 /* Have we gotten too many bus resets? */
2201 if (j == S1394_ISOCH_ALLOC_RETRIES) {
2202 *result = T1394_ENO_BANDWIDTH;
2203 /* Unlock the Isoch CEC member list */
2204 mutex_exit(&cec_curr->isoch_cec_mutex);
2205 return (DDI_FAILURE);
2206 }
2207
2208 cec_curr->realloc_valid = B_TRUE;
2209 cec_curr->realloc_chnl_num = chnl_num;
2210 cec_curr->realloc_bandwidth = cec_curr->bandwidth;
2211 cec_curr->realloc_speed = cec_curr->filter_current_speed;
2212
2213 setup_do_callbacks:
2214 /* Call all of the setup_target() callbacks */
2215 target_args.channel_num = chnl_num;
2216 target_args.channel_speed = cec_curr->filter_current_speed;
2217
2218 /* Now we are going into the callbacks */
2219 cec_curr->in_callbacks = B_TRUE;
2220
2221 /* Unlock the Isoch CEC member list */
2222 mutex_exit(&cec_curr->isoch_cec_mutex);
2223
2224 member_curr = cec_curr->cec_member_list_head;
2225 *result = 0;
2226 while (member_curr != NULL) {
2227 if (member_curr->isoch_cec_evts.setup_target != NULL) {
2228 setup_callback =
2229 member_curr->isoch_cec_evts.setup_target;
2230 ret = setup_callback(t1394_isoch_cec_hdl,
2231 member_curr->isoch_cec_evts_arg, &target_args);
2232 if (ret != DDI_SUCCESS)
2233 *result = T1394_ETARGET;
2234 }
2235 member_curr = member_curr->cec_mem_next;
2236 }
2237
2238 /* Lock the Isoch CEC member list */
2239 mutex_enter(&cec_curr->isoch_cec_mutex);
2240
2241 /* We are finished with the callbacks */
2242 cec_curr->in_callbacks = B_FALSE;
2243 if (cec_curr->cec_want_wakeup == B_TRUE) {
2244 cec_curr->cec_want_wakeup = B_FALSE;
2245 cv_broadcast(&cec_curr->in_callbacks_cv);
2246 }
2247
2248 /*
2249 * Now "start" and "teardown" are legal state transitions
2250 * and "join", "free", and "setup" are illegal state transitions
2251 */
2252 CEC_SET_LEGAL(cec_curr, (ISOCH_CEC_START | ISOCH_CEC_TEARDOWN));
2253 CEC_SET_ILLEGAL(cec_curr, (ISOCH_CEC_JOIN | ISOCH_CEC_FREE |
2254 ISOCH_CEC_SETUP));
2255
2256 /* Unlock the Isoch CEC member list */
2257 mutex_exit(&cec_curr->isoch_cec_mutex);
2258
2259 /* Return DDI_FAILURE if any targets failed setup */
2260 if (*result != 0) {
2261 return (DDI_FAILURE);
2262 }
2263
2264 return (DDI_SUCCESS);
2265 }
2266
2267 /*
2268 * Function: t1394_start_isoch_cec()
2269 * Input(s): t1394_hdl The target "handle" returned by
2270 * t1394_attach()
2271 * t1394_isoch_cec_hdl The Isoch CEC "handle" returned by
2272 * t1394_alloc_isoch_cec()
2273 * flags The flags parameter is unused (for now)
2274 *
2275 * Output(s): DDI_SUCCESS All start_target() callbacks returned
2276 * successfully
2277 * DDI_FAILURE One or more start_target() callbacks
2278 * returned failure
2279 *
2280 * Description: t1394_start_isoch_cec() directs the 1394 Software Framework
2281 * to invoke each of the start_target() callbacks, first for
2282 * each listener, then for the talker.
2283 */
2284 /* ARGSUSED */
2285 int
t1394_start_isoch_cec(t1394_handle_t t1394_hdl,t1394_isoch_cec_handle_t t1394_isoch_cec_hdl,uint_t flags)2286 t1394_start_isoch_cec(t1394_handle_t t1394_hdl,
2287 t1394_isoch_cec_handle_t t1394_isoch_cec_hdl, uint_t flags)
2288 {
2289 s1394_isoch_cec_t *cec_curr;
2290 s1394_isoch_cec_member_t *member_curr;
2291 int ret;
2292 boolean_t err;
2293 int (*start_callback)(t1394_isoch_cec_handle_t, opaque_t);
2294
2295 ASSERT(t1394_hdl != NULL);
2296 ASSERT(t1394_isoch_cec_hdl != NULL);
2297
2298 /* Convert the handle to an Isoch CEC pointer */
2299 cec_curr = (s1394_isoch_cec_t *)t1394_isoch_cec_hdl;
2300
2301 /* Lock the Isoch CEC member list */
2302 mutex_enter(&cec_curr->isoch_cec_mutex);
2303
2304 /* Are we in any callbacks? */
2305 if (CEC_IN_ANY_CALLBACKS(cec_curr)) {
2306 /* Unlock the Isoch CEC member list */
2307 mutex_exit(&cec_curr->isoch_cec_mutex);
2308 return (DDI_FAILURE);
2309 }
2310
2311 /* Is "start" a legal state transition? */
2312 if (CEC_TRANSITION_LEGAL(cec_curr, ISOCH_CEC_START) == 0) {
2313 /* Unlock the Isoch CEC member list */
2314 mutex_exit(&cec_curr->isoch_cec_mutex);
2315 return (DDI_FAILURE);
2316 }
2317
2318 /* Now we are going into the callbacks */
2319 cec_curr->in_callbacks = B_TRUE;
2320
2321 /* Unlock the Isoch CEC member list */
2322 mutex_exit(&cec_curr->isoch_cec_mutex);
2323
2324 /*
2325 * Call all of the start_target() callbacks
2326 * Start at the tail (listeners first) and
2327 * go toward the head (talker last)
2328 */
2329 member_curr = cec_curr->cec_member_list_tail;
2330 err = B_FALSE;
2331 while (member_curr != NULL) {
2332 if (member_curr->isoch_cec_evts.start_target != NULL) {
2333 start_callback =
2334 member_curr->isoch_cec_evts.start_target;
2335 ret = start_callback(t1394_isoch_cec_hdl,
2336 member_curr->isoch_cec_evts_arg);
2337 if (ret != DDI_SUCCESS)
2338 err = B_TRUE;
2339 }
2340 member_curr = member_curr->cec_mem_prev;
2341 }
2342
2343 /* Lock the Isoch CEC member list */
2344 mutex_enter(&cec_curr->isoch_cec_mutex);
2345
2346 /* We are finished with the callbacks */
2347 cec_curr->in_callbacks = B_FALSE;
2348 if (cec_curr->cec_want_wakeup == B_TRUE) {
2349 cec_curr->cec_want_wakeup = B_FALSE;
2350 cv_broadcast(&cec_curr->in_callbacks_cv);
2351 }
2352
2353 /*
2354 * Now "stop" is a legal state transitions
2355 * and "start" and "teardown" are illegal state transitions
2356 */
2357 CEC_SET_LEGAL(cec_curr, ISOCH_CEC_STOP);
2358 CEC_SET_ILLEGAL(cec_curr, (ISOCH_CEC_START | ISOCH_CEC_TEARDOWN));
2359
2360 /* Unlock the Isoch CEC member list */
2361 mutex_exit(&cec_curr->isoch_cec_mutex);
2362
2363 /* Return DDI_FAILURE if any targets failed start */
2364 if (err == B_TRUE) {
2365 return (DDI_FAILURE);
2366 }
2367
2368 return (DDI_SUCCESS);
2369 }
2370
2371 /*
2372 * Function: t1394_stop_isoch_cec()
2373 * Input(s): t1394_hdl The target "handle" returned by
2374 * t1394_attach()
2375 * t1394_isoch_cec_hdl The Isoch CEC "handle" returned by
2376 * t1394_alloc_isoch_cec()
2377 * flags The flags parameter is unused (for now)
2378 *
2379 * Output(s): DDI_SUCCESS Target successfully stopped the
2380 * Isoch CEC
2381 * DDI_FAILURE Target failed to stop the Isoch CEC
2382 *
2383 * Description: t1394_stop_isoch_cec() directs the 1394 Software Framework
2384 * to invoke each of the stop_target() callbacks, first for
2385 * the talker, then for each listener.
2386 * (This call will fail if it is called at an
2387 * inappropriate time, i.e. before the t1394_start_isoch_cec()
2388 * call, etc.)
2389 */
2390 /* ARGSUSED */
2391 int
t1394_stop_isoch_cec(t1394_handle_t t1394_hdl,t1394_isoch_cec_handle_t t1394_isoch_cec_hdl,uint_t flags)2392 t1394_stop_isoch_cec(t1394_handle_t t1394_hdl,
2393 t1394_isoch_cec_handle_t t1394_isoch_cec_hdl, uint_t flags)
2394 {
2395 s1394_isoch_cec_t *cec_curr;
2396 s1394_isoch_cec_member_t *member_curr;
2397 void (*stop_callback)(t1394_isoch_cec_handle_t, opaque_t);
2398
2399 ASSERT(t1394_hdl != NULL);
2400 ASSERT(t1394_isoch_cec_hdl != NULL);
2401
2402 /* Convert the handle to an Isoch CEC pointer */
2403 cec_curr = (s1394_isoch_cec_t *)t1394_isoch_cec_hdl;
2404
2405 /* Lock the Isoch CEC member list */
2406 mutex_enter(&cec_curr->isoch_cec_mutex);
2407
2408 /* Are we in any callbacks? */
2409 if (CEC_IN_ANY_CALLBACKS(cec_curr)) {
2410 /* Unlock the Isoch CEC member list */
2411 mutex_exit(&cec_curr->isoch_cec_mutex);
2412 return (DDI_FAILURE);
2413 }
2414
2415 /* Is "stop" a legal state transition? */
2416 if (CEC_TRANSITION_LEGAL(cec_curr, ISOCH_CEC_STOP) == 0) {
2417 /* Unlock the Isoch CEC member list */
2418 mutex_exit(&cec_curr->isoch_cec_mutex);
2419 return (DDI_FAILURE);
2420 }
2421
2422 /* Now we are going into the callbacks */
2423 cec_curr->in_callbacks = B_TRUE;
2424
2425 /* Unlock the Isoch CEC member list */
2426 mutex_exit(&cec_curr->isoch_cec_mutex);
2427
2428 /*
2429 * Call all of the stop_target() callbacks
2430 * Start at the head (talker first) and
2431 * go toward the tail (listeners last)
2432 */
2433 member_curr = cec_curr->cec_member_list_head;
2434 while (member_curr != NULL) {
2435 if (member_curr->isoch_cec_evts.stop_target != NULL) {
2436 stop_callback =
2437 member_curr->isoch_cec_evts.stop_target;
2438 stop_callback(t1394_isoch_cec_hdl,
2439 member_curr->isoch_cec_evts_arg);
2440 }
2441 member_curr = member_curr->cec_mem_next;
2442 }
2443
2444 /* Lock the Isoch CEC member list */
2445 mutex_enter(&cec_curr->isoch_cec_mutex);
2446
2447 /* We are finished with the callbacks */
2448 cec_curr->in_callbacks = B_FALSE;
2449 if (cec_curr->cec_want_wakeup == B_TRUE) {
2450 cec_curr->cec_want_wakeup = B_FALSE;
2451 cv_broadcast(&cec_curr->in_callbacks_cv);
2452 }
2453
2454 /*
2455 * Now "start" and "teardown" are legal state transitions
2456 * and "stop" is an illegal state transitions
2457 */
2458 CEC_SET_LEGAL(cec_curr, (ISOCH_CEC_START | ISOCH_CEC_TEARDOWN));
2459 CEC_SET_ILLEGAL(cec_curr, ISOCH_CEC_STOP);
2460
2461 /* Unlock the Isoch CEC member list */
2462 mutex_exit(&cec_curr->isoch_cec_mutex);
2463
2464 return (DDI_SUCCESS);
2465 }
2466
2467 /*
2468 * Function: t1394_teardown_isoch_cec()
2469 * Input(s): t1394_hdl The target "handle" returned by
2470 * t1394_attach()
2471 * t1394_isoch_cec_hdl The Isoch CEC "handle" returned by
2472 * t1394_alloc_isoch_cec()
2473 * flags The flags parameter is unused (for now)
2474 *
2475 * Output(s): DDI_SUCCESS Target successfully tore down the
2476 * Isoch CEC
2477 * DDI_FAILURE Target failed to tear down the
2478 * Isoch CEC
2479 *
2480 * Description: t1394_teardown_isoch_cec() directs the 1394 Software Framework
2481 * to free up any isochronous resources we might be holding and
2482 * call all of the teardown_target() callbacks.
2483 * (This call will fail if it is called at an
2484 * inappropriate time, i.e. before the t1394_start_isoch_cec()
2485 * call, before the t1394_stop_isoch_cec, etc.
2486 */
2487 /* ARGSUSED */
2488 int
t1394_teardown_isoch_cec(t1394_handle_t t1394_hdl,t1394_isoch_cec_handle_t t1394_isoch_cec_hdl,uint_t flags)2489 t1394_teardown_isoch_cec(t1394_handle_t t1394_hdl,
2490 t1394_isoch_cec_handle_t t1394_isoch_cec_hdl, uint_t flags)
2491 {
2492 s1394_hal_t *hal;
2493 s1394_isoch_cec_t *cec_curr;
2494 s1394_isoch_cec_member_t *member_curr;
2495 uint32_t chnl_mask;
2496 uint32_t old_chnl_mask;
2497 uint_t bw_alloc_units;
2498 uint_t generation;
2499 int ret;
2500 int err;
2501 void (*teardown_callback)(t1394_isoch_cec_handle_t, opaque_t);
2502
2503 ASSERT(t1394_hdl != NULL);
2504 ASSERT(t1394_isoch_cec_hdl != NULL);
2505
2506 hal = ((s1394_target_t *)t1394_hdl)->on_hal;
2507
2508 /* Convert the handle to an Isoch CEC pointer */
2509 cec_curr = (s1394_isoch_cec_t *)t1394_isoch_cec_hdl;
2510
2511 /* Lock the Isoch CEC member list */
2512 mutex_enter(&cec_curr->isoch_cec_mutex);
2513
2514 /* Are we in any callbacks? */
2515 if (CEC_IN_ANY_CALLBACKS(cec_curr)) {
2516 /* Unlock the Isoch CEC member list */
2517 mutex_exit(&cec_curr->isoch_cec_mutex);
2518 return (DDI_FAILURE);
2519 }
2520
2521 /* Is "teardown" a legal state transition? */
2522 if (CEC_TRANSITION_LEGAL(cec_curr, ISOCH_CEC_TEARDOWN) == 0) {
2523 /* Unlock the Isoch CEC member list */
2524 mutex_exit(&cec_curr->isoch_cec_mutex);
2525 return (DDI_FAILURE);
2526 }
2527
2528 /* If T1394_NO_IRM_ALLOC is set then don't free... do callbacks */
2529 if (cec_curr->cec_options & T1394_NO_IRM_ALLOC) {
2530 goto teardown_do_callbacks;
2531 }
2532
2533 /* If nothing has been allocated or we failed to */
2534 /* reallocate, then we are done... call the callbacks */
2535 if ((cec_curr->realloc_valid == B_FALSE) ||
2536 (cec_curr->realloc_failed == B_TRUE)) {
2537 goto teardown_do_callbacks;
2538 }
2539
2540 /*
2541 * Get the current generation number - don't need the
2542 * topology tree mutex here because it is read-only, and
2543 * there is a race condition with or without it.
2544 */
2545 generation = hal->generation_count;
2546
2547 /* Compute the amount bandwidth to free */
2548 bw_alloc_units = s1394_compute_bw_alloc_units(hal,
2549 cec_curr->bandwidth, cec_curr->realloc_speed);
2550
2551 /* Check that the generation has not changed - */
2552 /* don't need the lock (read only) */
2553 if (generation != hal->generation_count)
2554 goto teardown_do_callbacks;
2555
2556 /* Unlock the Isoch CEC member list */
2557 mutex_exit(&cec_curr->isoch_cec_mutex);
2558
2559 /* Try to free up the bandwidth */
2560 ret = s1394_bandwidth_free(hal, bw_alloc_units, generation, &err);
2561
2562 /* Lock the Isoch CEC member list */
2563 mutex_enter(&cec_curr->isoch_cec_mutex);
2564
2565 if (ret == DDI_FAILURE) {
2566 if (err == CMD1394_EBUSRESET) {
2567 goto teardown_do_callbacks;
2568 }
2569 }
2570
2571 /* Free the allocated channel */
2572 chnl_mask = (1 << ((63 - cec_curr->realloc_chnl_num) % 32));
2573
2574 /* Unlock the Isoch CEC member list */
2575 mutex_exit(&cec_curr->isoch_cec_mutex);
2576 if (cec_curr->realloc_chnl_num < 32) {
2577 ret = s1394_channel_free(hal, chnl_mask, generation,
2578 S1394_CHANNEL_ALLOC_HI, &old_chnl_mask, &err);
2579 } else {
2580 ret = s1394_channel_free(hal, chnl_mask, generation,
2581 S1394_CHANNEL_ALLOC_LO, &old_chnl_mask, &err);
2582 }
2583 /* Lock the Isoch CEC member list */
2584 mutex_enter(&cec_curr->isoch_cec_mutex);
2585
2586 teardown_do_callbacks:
2587 /* From here on reallocation is unnecessary */
2588 cec_curr->realloc_valid = B_FALSE;
2589 cec_curr->realloc_chnl_num = 0;
2590 cec_curr->realloc_bandwidth = 0;
2591
2592 /* Now we are going into the callbacks */
2593 cec_curr->in_callbacks = B_TRUE;
2594
2595 /* Unlock the Isoch CEC member list */
2596 mutex_exit(&cec_curr->isoch_cec_mutex);
2597
2598 /* Call all of the teardown_target() callbacks */
2599 member_curr = cec_curr->cec_member_list_head;
2600 while (member_curr != NULL) {
2601 if (member_curr->isoch_cec_evts.teardown_target != NULL) {
2602 teardown_callback =
2603 member_curr->isoch_cec_evts.teardown_target;
2604 teardown_callback(t1394_isoch_cec_hdl,
2605 member_curr->isoch_cec_evts_arg);
2606 }
2607 member_curr = member_curr->cec_mem_next;
2608 }
2609
2610 /* Lock the Isoch CEC member list */
2611 mutex_enter(&cec_curr->isoch_cec_mutex);
2612
2613 /* We are finished with the callbacks */
2614 cec_curr->in_callbacks = B_FALSE;
2615 if (cec_curr->cec_want_wakeup == B_TRUE) {
2616 cec_curr->cec_want_wakeup = B_FALSE;
2617 cv_broadcast(&cec_curr->in_callbacks_cv);
2618 }
2619
2620 /*
2621 * Now "join" and "setup" are legal state transitions
2622 * and "start" and "teardown" are illegal state transitions
2623 */
2624 CEC_SET_LEGAL(cec_curr, (ISOCH_CEC_JOIN | ISOCH_CEC_SETUP));
2625 CEC_SET_ILLEGAL(cec_curr, (ISOCH_CEC_START | ISOCH_CEC_TEARDOWN));
2626
2627 /* And if the member list is empty, then "free" is legal too */
2628 if ((cec_curr->cec_member_list_head == NULL) &&
2629 (cec_curr->cec_member_list_tail == NULL)) {
2630 CEC_SET_LEGAL(cec_curr, ISOCH_CEC_FREE);
2631 }
2632
2633 /* Unlock the Isoch CEC member list */
2634 mutex_exit(&cec_curr->isoch_cec_mutex);
2635 return (DDI_SUCCESS);
2636 }
2637
2638 /*
2639 * Function: t1394_alloc_isoch_dma()
2640 * Input(s): t1394_hdl The target "handle" returned by
2641 * t1394_attach()
2642 * idi This structure contains information
2643 * for configuring the data flow for
2644 * isochronous DMA
2645 * flags The flags parameter is unused (for now)
2646 *
2647 * Output(s): t1394_idma_hdl The IDMA "handle" used in all
2648 * subsequent isoch_dma() calls
2649 * result Used to pass more specific info back
2650 * to target
2651 *
2652 * Description: t1394_alloc_isoch_dma() allocates and initializes an
2653 * isochronous DMA resource for transmitting or receiving
2654 * isochronous data. If it fails, result may hold
2655 * T1394_EIDMA_NO_RESRCS, indicating that no isoch DMA resource
2656 * are available.
2657 */
2658 /* ARGSUSED */
2659 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)2660 t1394_alloc_isoch_dma(t1394_handle_t t1394_hdl,
2661 id1394_isoch_dmainfo_t *idi, uint_t flags,
2662 t1394_isoch_dma_handle_t *t1394_idma_hdl, int *result)
2663 {
2664 s1394_hal_t *hal;
2665 int ret;
2666
2667 ASSERT(t1394_hdl != NULL);
2668 ASSERT(idi != NULL);
2669 ASSERT(t1394_idma_hdl != NULL);
2670
2671 /* Find the HAL this target resides on */
2672 hal = ((s1394_target_t *)t1394_hdl)->on_hal;
2673
2674 /* Sanity check dma options. If talk enabled, listen should be off */
2675 if ((idi->idma_options & ID1394_TALK) &&
2676 (idi->idma_options != ID1394_TALK)) {
2677 *result = T1394_EIDMA_CONFLICT;
2678 return (DDI_FAILURE);
2679 }
2680
2681 /* Only one listen mode allowed */
2682 if ((idi->idma_options & ID1394_LISTEN_PKT_MODE) &&
2683 (idi->idma_options & ID1394_LISTEN_BUF_MODE)) {
2684 *result = T1394_EIDMA_CONFLICT;
2685 return (DDI_FAILURE);
2686 }
2687
2688 /* Have HAL alloc a resource and compile ixl */
2689 ret = HAL_CALL(hal).alloc_isoch_dma(hal->halinfo.hal_private, idi,
2690 (void **)t1394_idma_hdl, result);
2691
2692 if (ret != DDI_SUCCESS) {
2693 if (*result == IXL1394_ENO_DMA_RESRCS) {
2694 *result = T1394_EIDMA_NO_RESRCS;
2695 }
2696 }
2697
2698 return (ret);
2699 }
2700
2701 /*
2702 * Function: t1394_free_isoch_dma()
2703 * Input(s): t1394_hdl The target "handle" returned by
2704 * t1394_attach()
2705 * flags The flags parameter is unused (for now)
2706 * t1394_idma_hdl The IDMA "handle" returned by
2707 * t1394_alloc_isoch_dma()
2708 *
2709 * Output(s): None
2710 *
2711 * Description: t1394_free_isoch_dma() is used to free all DMA resources
2712 * allocated for the isoch stream associated with t1394_idma_hdl.
2713 */
2714 /* ARGSUSED */
2715 void
t1394_free_isoch_dma(t1394_handle_t t1394_hdl,uint_t flags,t1394_isoch_dma_handle_t * t1394_idma_hdl)2716 t1394_free_isoch_dma(t1394_handle_t t1394_hdl, uint_t flags,
2717 t1394_isoch_dma_handle_t *t1394_idma_hdl)
2718 {
2719 s1394_hal_t *hal;
2720
2721 ASSERT(t1394_hdl != NULL);
2722 ASSERT(*t1394_idma_hdl != NULL);
2723
2724 /* Find the HAL this target resides on */
2725 hal = ((s1394_target_t *)t1394_hdl)->on_hal;
2726
2727 /* Tell HAL to release local isoch dma resources */
2728 HAL_CALL(hal).free_isoch_dma(hal->halinfo.hal_private, *t1394_idma_hdl);
2729
2730 /* Null out isoch handle */
2731 *t1394_idma_hdl = NULL;
2732 }
2733
2734 /*
2735 * Function: t1394_start_isoch_dma()
2736 * Input(s): t1394_hdl The target "handle" returned by
2737 * t1394_attach()
2738 * t1394_idma_hdl The IDMA "handle" returned by
2739 * t1394_alloc_isoch_dma()
2740 * idma_ctrlinfo This structure contains control args
2741 * used when starting isoch DMA for
2742 * the allocated resource
2743 * flags One flag defined - ID1394_START_ON_CYCLE
2744 *
2745 * Output(s): result Used to pass more specific info back
2746 * to target
2747 *
2748 * Description: t1394_start_isoch_dma() is used to start DMA for the isoch
2749 * stream associated with t1394_idma_hdl.
2750 */
2751 /* ARGSUSED */
2752 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)2753 t1394_start_isoch_dma(t1394_handle_t t1394_hdl,
2754 t1394_isoch_dma_handle_t t1394_idma_hdl,
2755 id1394_isoch_dma_ctrlinfo_t *idma_ctrlinfo, uint_t flags,
2756 int *result)
2757 {
2758 s1394_hal_t *hal;
2759 int ret;
2760
2761 ASSERT(t1394_hdl != NULL);
2762 ASSERT(t1394_idma_hdl != NULL);
2763 ASSERT(idma_ctrlinfo != NULL);
2764
2765 /* Find the HAL this target resides on */
2766 hal = ((s1394_target_t *)t1394_hdl)->on_hal;
2767
2768 ret = HAL_CALL(hal).start_isoch_dma(hal->halinfo.hal_private,
2769 (void *)t1394_idma_hdl, idma_ctrlinfo, flags, result);
2770
2771 return (ret);
2772 }
2773
2774 /*
2775 * Function: t1394_stop_isoch_dma()
2776 * Input(s): t1394_hdl The target "handle" returned by
2777 * t1394_attach()
2778 * t1394_idma_hdl The IDMA "handle" returned by
2779 * t1394_alloc_isoch_dma()
2780 * flags The flags parameter is unused (for now)
2781 *
2782 * Output(s): None
2783 *
2784 * Description: t1394_stop_isoch_dma() is used to stop DMA for the isoch
2785 * stream associated with t1394_idma_hdl.
2786 */
2787 /* ARGSUSED */
2788 void
t1394_stop_isoch_dma(t1394_handle_t t1394_hdl,t1394_isoch_dma_handle_t t1394_idma_hdl,uint_t flags)2789 t1394_stop_isoch_dma(t1394_handle_t t1394_hdl,
2790 t1394_isoch_dma_handle_t t1394_idma_hdl, uint_t flags)
2791 {
2792 s1394_hal_t *hal;
2793 int result;
2794
2795 ASSERT(t1394_hdl != NULL);
2796 ASSERT(t1394_idma_hdl != NULL);
2797
2798 /* Find the HAL this target resides on */
2799 hal = ((s1394_target_t *)t1394_hdl)->on_hal;
2800
2801 HAL_CALL(hal).stop_isoch_dma(hal->halinfo.hal_private,
2802 (void *)t1394_idma_hdl, &result);
2803 }
2804
2805 /*
2806 * Function: t1394_update_isoch_dma()
2807 * Input(s): t1394_hdl The target "handle" returned by
2808 * t1394_attach()
2809 * t1394_idma_hdl The IDMA "handle" returned by
2810 * t1394_alloc_isoch_dma()
2811 * idma_updateinfo This structure contains ixl command args
2812 * used when updating args in an
2813 * existing list of ixl commands with
2814 * args in a new list of ixl commands.
2815 * flags The flags parameter is unused (for now)
2816 *
2817 * Output(s): result Used to pass more specific info back
2818 * to target
2819 *
2820 * Description: t1394_update_isoch_dma() is used to alter an IXL program that
2821 * has already been built (compiled) by t1394_alloc_isoch_dma().
2822 */
2823 /* ARGSUSED */
2824 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)2825 t1394_update_isoch_dma(t1394_handle_t t1394_hdl,
2826 t1394_isoch_dma_handle_t t1394_idma_hdl,
2827 id1394_isoch_dma_updateinfo_t *idma_updateinfo, uint_t flags,
2828 int *result)
2829 {
2830 s1394_hal_t *hal;
2831 int ret;
2832
2833 ASSERT(t1394_hdl != NULL);
2834 ASSERT(t1394_idma_hdl != NULL);
2835 ASSERT(idma_updateinfo != NULL);
2836
2837 /* Find the HAL this target resides on */
2838 hal = ((s1394_target_t *)t1394_hdl)->on_hal;
2839
2840 ret = HAL_CALL(hal).update_isoch_dma(hal->halinfo.hal_private,
2841 (void *)t1394_idma_hdl, idma_updateinfo, flags, result);
2842
2843 return (ret);
2844 }
2845
2846 /*
2847 * Function: t1394_initiate_bus_reset()
2848 * Input(s): t1394_hdl The target "handle" returned by
2849 * t1394_attach()
2850 * flags The flags parameter is unused (for now)
2851 *
2852 * Output(s): None
2853 *
2854 * Description: t1394_initiate_bus_reset() determines whether the local
2855 * device has a P1394A PHY and will support the arbitrated
2856 * short bus reset. If not, it will initiate a normal bus reset.
2857 */
2858 /* ARGSUSED */
2859 void
t1394_initiate_bus_reset(t1394_handle_t t1394_hdl,uint_t flags)2860 t1394_initiate_bus_reset(t1394_handle_t t1394_hdl, uint_t flags)
2861 {
2862 s1394_hal_t *hal;
2863
2864 ASSERT(t1394_hdl != NULL);
2865
2866 /* Find the HAL this target resides on */
2867 hal = ((s1394_target_t *)t1394_hdl)->on_hal;
2868
2869 /* Reset the bus */
2870 if (hal->halinfo.phy == H1394_PHY_1394A) {
2871 (void) HAL_CALL(hal).short_bus_reset(hal->halinfo.hal_private);
2872 } else {
2873 (void) HAL_CALL(hal).bus_reset(hal->halinfo.hal_private);
2874 }
2875 }
2876
2877 /*
2878 * Function: t1394_get_topology_map()
2879 * Input(s): t1394_hdl The target "handle" returned by
2880 * t1394_attach()
2881 * bus_generation The current generation
2882 * tm_length The size of the tm_buffer given
2883 * flags The flags parameter is unused (for now)
2884 *
2885 * Output(s): tm_buffer Filled in by the 1394 Software Framework
2886 * with the contents of the local
2887 * TOPOLOGY_MAP
2888 *
2889 * Description: t1394_get_topology_map() returns the 1394 TOPLOGY_MAP. See
2890 * IEEE 1394-1995 Section 8.2.3.4.1 for format information. This
2891 * call can fail if there is a generation mismatch or the
2892 * tm_buffer is too small to hold the TOPOLOGY_MAP.
2893 */
2894 /* ARGSUSED */
2895 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)2896 t1394_get_topology_map(t1394_handle_t t1394_hdl, uint_t bus_generation,
2897 size_t tm_length, uint_t flags, uint32_t *tm_buffer)
2898 {
2899 s1394_hal_t *hal;
2900 uint32_t *tm_ptr;
2901 uint_t length;
2902
2903 ASSERT(t1394_hdl != NULL);
2904
2905 /* Find the HAL this target resides on */
2906 hal = ((s1394_target_t *)t1394_hdl)->on_hal;
2907
2908 /* Lock the topology tree */
2909 mutex_enter(&hal->topology_tree_mutex);
2910
2911 /* Check the bus_generation for the Topology Map */
2912 if (bus_generation != hal->generation_count) {
2913 /* Unlock the topology tree */
2914 mutex_exit(&hal->topology_tree_mutex);
2915 return (DDI_FAILURE);
2916 }
2917
2918 tm_ptr = (uint32_t *)hal->CSR_topology_map;
2919 length = tm_ptr[0] >> 16;
2920 length = length * 4; /* Bytes instead of quadlets */
2921 length = length + 4; /* don't forget the first quad */
2922
2923 /* Check that the buffer is big enough */
2924 if (length > (uint_t)tm_length) {
2925 /* Unlock the topology tree */
2926 mutex_exit(&hal->topology_tree_mutex);
2927 return (DDI_FAILURE);
2928 }
2929
2930 /* Do the copy */
2931 bcopy(tm_ptr, tm_buffer, length);
2932
2933 /* Unlock the topology tree */
2934 mutex_exit(&hal->topology_tree_mutex);
2935 return (DDI_SUCCESS);
2936 }
2937
2938 /*
2939 * Function: t1394_CRC16()
2940 * Input(s): d The data to compute the CRC-16 for
2941 * crc_length The length into the data to compute for
2942 * flags The flags parameter is unused (for now)
2943 *
2944 * Output(s): CRC The CRC-16 computed for the length
2945 * of data specified
2946 *
2947 * Description: t1394_CRC16() implements ISO/IEC 13213:1994, ANSI/IEEE Std
2948 * 1212, 1994 - 8.1.5.
2949 */
2950 /* ARGSUSED */
2951 uint_t
t1394_CRC16(uint32_t * d,size_t crc_length,uint_t flags)2952 t1394_CRC16(uint32_t *d, size_t crc_length, uint_t flags)
2953 {
2954 /* Implements ISO/IEC 13213:1994, */
2955 /* ANSI/IEEE Std 1212, 1994 - 8.1.5 */
2956 uint_t ret;
2957
2958 ret = s1394_CRC16((uint_t *)d, (uint_t)crc_length);
2959
2960 return (ret);
2961 }
2962
2963 /*
2964 * Function: t1394_add_cfgrom_entry()
2965 * Input(s): t1394_hdl The target "handle" returned by
2966 * t1394_attach()
2967 * cfgrom_entryinfo This structure holds the cfgrom key,
2968 * buffer, and size
2969 * flags The flags parameter is unused (for now)
2970 *
2971 * Output(s): t1394_cfgrom_hdl The ConfigROM "handle" used in
2972 * t1394_rem_cfgrom_entry()
2973 * result Used to pass more specific info back
2974 * to target
2975 *
2976 * Description: t1394_add_cfgrom_entry() adds an entry to the local Config ROM,
2977 * updating the directory entries as necessary. This call could
2978 * fail because there is no room for the new entry in Config ROM
2979 * (T1394_ECFGROM_FULL), the key is invalid (T1394_EINVALID_PARAM),
2980 * or it was called in interrupt context (T1394_EINVALID_CONTEXT).
2981 */
2982 /* ARGSUSED */
2983 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)2984 t1394_add_cfgrom_entry(t1394_handle_t t1394_hdl,
2985 t1394_cfgrom_entryinfo_t *cfgrom_entryinfo, uint_t flags,
2986 t1394_cfgrom_handle_t *t1394_cfgrom_hdl, int *result)
2987 {
2988 s1394_hal_t *hal;
2989 s1394_target_t *target;
2990 int ret;
2991 uint_t key;
2992 uint_t size;
2993 uint32_t *buffer;
2994
2995 ASSERT(t1394_hdl != NULL);
2996
2997 target = (s1394_target_t *)t1394_hdl;
2998
2999 key = cfgrom_entryinfo->ce_key;
3000 buffer = cfgrom_entryinfo->ce_buffer;
3001 size = (uint_t)cfgrom_entryinfo->ce_size;
3002
3003 /* Check for a valid size */
3004 if (size == 0) {
3005 *result = T1394_EINVALID_PARAM;
3006 return (DDI_FAILURE);
3007 }
3008
3009 /* Check for a valid key type */
3010 if (((key << IEEE1212_KEY_VALUE_SHIFT) & IEEE1212_KEY_TYPE_MASK) == 0) {
3011 *result = T1394_EINVALID_PARAM;
3012 return (DDI_FAILURE);
3013 }
3014
3015 /* Find the HAL this target resides on */
3016 hal = target->on_hal;
3017
3018 /* Is this on the interrupt stack? */
3019 if (servicing_interrupt()) {
3020 *result = T1394_EINVALID_CONTEXT;
3021 return (DDI_FAILURE);
3022 }
3023
3024 /* Lock the Config ROM buffer */
3025 mutex_enter(&hal->local_config_rom_mutex);
3026
3027 ret = s1394_add_config_rom_entry(hal, key, buffer, size,
3028 (void **)t1394_cfgrom_hdl, result);
3029 if (ret != DDI_SUCCESS) {
3030 if (*result == CMD1394_ERSRC_CONFLICT)
3031 *result = T1394_ECFGROM_FULL;
3032 mutex_exit(&hal->local_config_rom_mutex);
3033
3034 return (ret);
3035 }
3036
3037 /* Setup the timeout function */
3038 if (hal->config_rom_timer_set == B_FALSE) {
3039 hal->config_rom_timer_set = B_TRUE;
3040 mutex_exit(&hal->local_config_rom_mutex);
3041 hal->config_rom_timer =
3042 timeout(s1394_update_config_rom_callback, hal,
3043 drv_usectohz(CONFIG_ROM_UPDATE_DELAY * 1000));
3044 } else {
3045 mutex_exit(&hal->local_config_rom_mutex);
3046 }
3047
3048 return (ret);
3049 }
3050
3051 /*
3052 * Function: t1394_rem_cfgrom_entry()
3053 * Input(s): t1394_hdl The target "handle" returned by
3054 * t1394_attach()
3055 * flags The flags parameter is unused (for now)
3056 * t1394_cfgrom_hdl The ConfigROM "handle" returned by
3057 * t1394_add_cfgrom_entry()
3058 *
3059 * Output(s): result Used to pass more specific info back
3060 * to target
3061 *
3062 * Description: t1394_rem_cfgrom_entry() is used to remove a previously added
3063 * Config ROM entry (indicated by t1394_cfgrom_hdl).
3064 */
3065 /* ARGSUSED */
3066 int
t1394_rem_cfgrom_entry(t1394_handle_t t1394_hdl,uint_t flags,t1394_cfgrom_handle_t * t1394_cfgrom_hdl,int * result)3067 t1394_rem_cfgrom_entry(t1394_handle_t t1394_hdl, uint_t flags,
3068 t1394_cfgrom_handle_t *t1394_cfgrom_hdl, int *result)
3069 {
3070 s1394_hal_t *hal;
3071 s1394_target_t *target;
3072 int ret;
3073
3074 ASSERT(t1394_hdl != NULL);
3075
3076 target = (s1394_target_t *)t1394_hdl;
3077
3078 /* Find the HAL this target resides on */
3079 hal = target->on_hal;
3080
3081 /* Is this on the interrupt stack? */
3082 if (servicing_interrupt()) {
3083 *result = T1394_EINVALID_CONTEXT;
3084 return (DDI_FAILURE);
3085 }
3086
3087 /* Lock the Config ROM buffer */
3088 mutex_enter(&hal->local_config_rom_mutex);
3089
3090 ret = s1394_remove_config_rom_entry(hal, (void **)t1394_cfgrom_hdl,
3091 result);
3092 if (ret != DDI_SUCCESS) {
3093 mutex_exit(&hal->local_config_rom_mutex);
3094 return (ret);
3095 }
3096
3097 /* Setup the timeout function */
3098 if (hal->config_rom_timer_set == B_FALSE) {
3099 hal->config_rom_timer_set = B_TRUE;
3100 mutex_exit(&hal->local_config_rom_mutex);
3101 hal->config_rom_timer =
3102 timeout(s1394_update_config_rom_callback, hal,
3103 drv_usectohz(CONFIG_ROM_UPDATE_DELAY * 1000));
3104 } else {
3105 mutex_exit(&hal->local_config_rom_mutex);
3106 }
3107
3108 return (ret);
3109 }
3110
3111 /*
3112 * Function: t1394_get_targetinfo()
3113 * Input(s): t1394_hdl The target "handle" returned by
3114 * t1394_attach()
3115 * bus_generation The current generation
3116 * flags The flags parameter is unused (for now)
3117 *
3118 * Output(s): targetinfo Structure containing max_payload,
3119 * max_speed, and target node ID.
3120 *
3121 * Description: t1394_get_targetinfo() is used to retrieve information specific
3122 * to a target device. It will fail if the generation given
3123 * does not match the current generation.
3124 */
3125 /* ARGSUSED */
3126 int
t1394_get_targetinfo(t1394_handle_t t1394_hdl,uint_t bus_generation,uint_t flags,t1394_targetinfo_t * targetinfo)3127 t1394_get_targetinfo(t1394_handle_t t1394_hdl, uint_t bus_generation,
3128 uint_t flags, t1394_targetinfo_t *targetinfo)
3129 {
3130 s1394_hal_t *hal;
3131 s1394_target_t *target;
3132 uint_t dev;
3133 uint_t curr;
3134 uint_t from_node;
3135 uint_t to_node;
3136
3137 ASSERT(t1394_hdl != NULL);
3138
3139 /* Find the HAL this target resides on */
3140 hal = ((s1394_target_t *)t1394_hdl)->on_hal;
3141
3142 target = (s1394_target_t *)t1394_hdl;
3143
3144 /* Lock the topology tree */
3145 mutex_enter(&hal->topology_tree_mutex);
3146
3147 /* Check the bus_generation */
3148 if (bus_generation != hal->generation_count) {
3149 /* Unlock the topology tree */
3150 mutex_exit(&hal->topology_tree_mutex);
3151 return (DDI_FAILURE);
3152 }
3153
3154 rw_enter(&hal->target_list_rwlock, RW_READER);
3155 /*
3156 * If there is no node, report T1394_INVALID_NODEID for target_nodeID;
3157 * current_max_speed and current_max_payload are undefined for this
3158 * case.
3159 */
3160 if (((target->target_state & S1394_TARG_GONE) != 0) ||
3161 (target->on_node == NULL)) {
3162 targetinfo->target_nodeID = T1394_INVALID_NODEID;
3163 } else {
3164 targetinfo->target_nodeID =
3165 (target->on_hal->node_id & IEEE1394_BUS_NUM_MASK) |
3166 target->on_node->node_num;
3167
3168 from_node = (target->on_hal->node_id) & IEEE1394_NODE_NUM_MASK;
3169 to_node = target->on_node->node_num;
3170
3171 targetinfo->current_max_speed = (uint_t)s1394_speed_map_get(
3172 hal, from_node, to_node);
3173
3174 /* Get current_max_payload */
3175 s1394_get_maxpayload(target, &dev, &curr);
3176 targetinfo->current_max_payload = curr;
3177 }
3178
3179 rw_exit(&hal->target_list_rwlock);
3180 /* Unlock the topology tree */
3181 mutex_exit(&hal->topology_tree_mutex);
3182 return (DDI_SUCCESS);
3183 }
3184