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