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