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