xref: /titanic_44/usr/src/uts/common/io/1394/t1394.c (revision fcf3ce441efd61da9bb2884968af01cb7c1452cc)
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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