xref: /illumos-gate/usr/src/uts/common/io/1394/targets/av1394/av1394_cmp.c (revision 71815ce76261aa773c97600750fdce92334d1990)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License (the "License").
6  * You may not use this file except in compliance with the License.
7  *
8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9  * or http://www.opensolaris.org/os/licensing.
10  * See the License for the specific language governing permissions
11  * and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL HEADER in each
14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15  * If applicable, add the following below this CDDL HEADER, with the
16  * fields enclosed by brackets "[]" replaced with your own identifying
17  * information: Portions Copyright [yyyy] [name of copyright owner]
18  *
19  * CDDL HEADER END
20  */
21 /*
22  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
23  * Use is subject to license terms.
24  */
25 
26 /*
27  * av1394 CMP (Connection Management Procedures)
28  */
29 #include <sys/1394/targets/av1394/av1394_impl.h>
30 
31 /* configuration routines */
32 static void	av1394_cmp_cleanup(av1394_inst_t *icp);
33 
34 /* ioctl routines */
35 static int	av1394_ioctl_plug_init_local(av1394_inst_t *,
36 		iec61883_plug_init_t *);
37 static int	av1394_ioctl_plug_init_remote(av1394_inst_t *,
38 		iec61883_plug_init_t *);
39 
40 /* local PCR routines */
41 static int	av1394_pcr_init(av1394_inst_t *, int, uint32_t);
42 static void	av1394_pcr_fini(av1394_inst_t *, int);
43 static int	av1394_pcr_alloc_addr(av1394_inst_t *, uint64_t,
44 		t1394_addr_handle_t *);
45 static void	av1394_pcr_free_addr(av1394_inst_t *, t1394_addr_handle_t *);
46 static int	av1394_pcr_make_ph(int, int, int);
47 static int	av1394_pcr_ph2idx(int);
48 static av1394_pcr_t *av1394_pcr_ph2pcr(av1394_cmp_t *, int);
49 static uint64_t	av1394_pcr_idx2addr(int);
50 static int	av1394_pcr_idx2num(int);
51 static boolean_t av1394_pcr_idx_is_mpr(int);
52 static boolean_t av1394_pcr_ph_is_mpr(int);
53 static boolean_t av1394_pcr_ph_is_remote(int);
54 
55 /* callbacks */
56 static void	av1394_pcr_recv_read_request(cmd1394_cmd_t *);
57 static void	av1394_pcr_recv_lock_request(cmd1394_cmd_t *);
58 
59 /* remote PCR routines */
60 static int	av1394_pcr_remote_read(av1394_inst_t *, int, uint32_t *);
61 static int	av1394_pcr_remote_cas(av1394_inst_t *, int, uint32_t *,
62 		uint32_t, uint32_t);
63 
64 #define	AV1394_TNF_ENTER(func)	\
65 	TNF_PROBE_0_DEBUG(func##_enter, AV1394_TNF_CMP_STACK, "");
66 
67 #define	AV1394_TNF_EXIT(func)	\
68 	TNF_PROBE_0_DEBUG(func##_exit, AV1394_TNF_CMP_STACK, "");
69 
70 
71 int
72 av1394_cmp_init(av1394_inst_t *avp)
73 {
74 	av1394_cmp_t	*cmp = &avp->av_i.i_cmp;
75 	ddi_iblock_cookie_t ibc = avp->av_attachinfo.iblock_cookie;
76 	int		ret;
77 
78 	AV1394_TNF_ENTER(av1394_cmp_init);
79 
80 	ret = t1394_cmp_register(avp->av_t1394_hdl, NULL, 0);
81 
82 	if (ret == DDI_SUCCESS) {
83 		rw_init(&cmp->cmp_pcr_rwlock, NULL, RW_DRIVER, ibc);
84 	}
85 
86 	AV1394_TNF_EXIT(av1394_cmp_init);
87 	return (ret);
88 }
89 
90 void
91 av1394_cmp_fini(av1394_inst_t *avp)
92 {
93 	AV1394_TNF_ENTER(av1394_cmp_fini);
94 
95 	av1394_cmp_cleanup(avp);
96 
97 	AV1394_TNF_EXIT(av1394_cmp_fini);
98 }
99 
100 void
101 av1394_cmp_bus_reset(av1394_inst_t *avp)
102 {
103 	av1394_cmp_t	*cmp = &avp->av_i.i_cmp;
104 	int		i;
105 
106 	AV1394_TNF_ENTER(av1394_cmp_bus_reset);
107 
108 	/* reset PCR values */
109 	rw_enter(&cmp->cmp_pcr_rwlock, RW_WRITER);
110 	for (i = 0; i < NELEM(cmp->cmp_pcr); i++) {
111 		if ((i == AV1394_OMPR_IDX) || (i == AV1394_IMPR_IDX)) {
112 			continue;
113 		}
114 		if (cmp->cmp_pcr[i]) {
115 			if (i < AV1394_IMPR_IDX) {
116 				cmp->cmp_pcr[i]->pcr_val &=
117 				    ~AV1394_OPCR_BR_CLEAR_MASK;
118 			} else {
119 				cmp->cmp_pcr[i]->pcr_val &=
120 				    ~AV1394_IPCR_BR_CLEAR_MASK;
121 			}
122 		}
123 	}
124 	rw_exit(&cmp->cmp_pcr_rwlock);
125 
126 	AV1394_TNF_EXIT(av1394_cmp_bus_reset);
127 }
128 
129 /*
130  * on close, free iPCRs and oPCRs not finalized by application
131  */
132 void
133 av1394_cmp_close(av1394_inst_t *avp)
134 {
135 	av1394_cmp_t	*cmp = &avp->av_i.i_cmp;
136 	int		i;
137 
138 	rw_enter(&cmp->cmp_pcr_rwlock, RW_WRITER);
139 	for (i = 0; i < NELEM(cmp->cmp_pcr); i++) {
140 		if ((i == AV1394_OMPR_IDX) || (i == AV1394_IMPR_IDX)) {
141 			continue;
142 		}
143 		if (cmp->cmp_pcr[i]) {
144 			av1394_pcr_fini(avp, i);
145 		}
146 	}
147 	rw_exit(&cmp->cmp_pcr_rwlock);
148 }
149 
150 /*
151  *
152  * --- ioctls
153  *
154  * IEC61883_PLUG_INIT
155  */
156 int
157 av1394_ioctl_plug_init(av1394_inst_t *avp, void *arg, int mode)
158 {
159 	int		ret = 0;
160 	iec61883_plug_init_t pi;
161 
162 	if (ddi_copyin(arg, &pi, sizeof (pi), mode) != 0) {
163 		return (EFAULT);
164 	}
165 
166 	/* check arguments */
167 	if (((pi.pi_type != IEC61883_PLUG_IN) &&
168 	    (pi.pi_type != IEC61883_PLUG_OUT) &&
169 	    (pi.pi_type != IEC61883_PLUG_MASTER_IN) &&
170 	    (pi.pi_type != IEC61883_PLUG_MASTER_OUT)) ||
171 	    (((pi.pi_num < 0) || (pi.pi_num >= AV1394_NPCR)) &&
172 	    (pi.pi_num != IEC61883_PLUG_ANY))) {
173 		return (EINVAL);
174 	}
175 
176 	if (pi.pi_loc == IEC61883_LOC_LOCAL) {
177 		ret = av1394_ioctl_plug_init_local(avp, &pi);
178 	} else if (pi.pi_loc == IEC61883_LOC_REMOTE) {
179 		ret = av1394_ioctl_plug_init_remote(avp, &pi);
180 	} else {
181 		ret = EINVAL;
182 	}
183 
184 	if (ret == 0) {
185 		if (ddi_copyout(&pi, arg, sizeof (pi), mode) != 0) {
186 			ret = EFAULT;
187 		}
188 	}
189 
190 	return (ret);
191 }
192 
193 /*
194  * IEC61883_PLUG_FINI
195  */
196 /*ARGSUSED*/
197 int
198 av1394_ioctl_plug_fini(av1394_inst_t *avp, void *arg, int mode)
199 {
200 	av1394_cmp_t	*cmp = &avp->av_i.i_cmp;
201 	int		ret;
202 	int		ph;
203 
204 	ph = (int)(intptr_t)arg;
205 
206 	if (av1394_pcr_ph_is_remote(ph) || av1394_pcr_ph_is_mpr(ph)) {
207 		return (0);
208 	}
209 
210 	rw_enter(&cmp->cmp_pcr_rwlock, RW_WRITER);
211 	if (av1394_pcr_ph2pcr(cmp, ph) != NULL) {
212 		av1394_pcr_fini(avp, av1394_pcr_ph2idx(ph));
213 		ret = 0;
214 	} else {
215 		ret = EINVAL;
216 	}
217 	rw_exit(&cmp->cmp_pcr_rwlock);
218 
219 	return (ret);
220 }
221 
222 /*
223  * IEC61883_PLUG_REG_READ
224  */
225 int
226 av1394_ioctl_plug_reg_read(av1394_inst_t *avp, void *arg, int mode)
227 {
228 	av1394_cmp_t	*cmp = &avp->av_i.i_cmp;
229 	int		ret = 0;
230 	iec61883_plug_reg_val_t pr;
231 	int		ph;
232 	av1394_pcr_t	*pcr;
233 
234 	if (ddi_copyin(arg, &pr, sizeof (pr), mode) != 0) {
235 		return (EFAULT);
236 	}
237 	ph = pr.pr_handle;
238 
239 	if (av1394_pcr_ph_is_remote(ph)) {
240 		ret = av1394_pcr_remote_read(avp, ph, &pr.pr_val);
241 	} else {
242 		switch (av1394_pcr_ph2idx(ph)) {
243 		case AV1394_OMPR_IDX:
244 			ret = t1394_cmp_read(avp->av_t1394_hdl, T1394_CMP_OMPR,
245 			    &pr.pr_val);
246 			break;
247 		case AV1394_IMPR_IDX:
248 			ret = t1394_cmp_read(avp->av_t1394_hdl, T1394_CMP_IMPR,
249 			    &pr.pr_val);
250 			break;
251 		default:
252 			rw_enter(&cmp->cmp_pcr_rwlock, RW_READER);
253 			if ((pcr = av1394_pcr_ph2pcr(cmp, ph)) != NULL) {
254 				pr.pr_val = pcr->pcr_val;
255 			} else {
256 				ret = EINVAL;
257 			}
258 			rw_exit(&cmp->cmp_pcr_rwlock);
259 		}
260 	}
261 
262 	if (ret == 0) {
263 		if (ddi_copyout(&pr, arg, sizeof (pr), mode) != 0) {
264 			ret = EFAULT;
265 		}
266 	}
267 
268 	return (ret);
269 }
270 
271 /*
272  * IEC61883_PLUG_REG_CAS
273  */
274 int
275 av1394_ioctl_plug_reg_cas(av1394_inst_t *avp, void *arg, int mode)
276 {
277 	av1394_cmp_t	*cmp = &avp->av_i.i_cmp;
278 	int		ret = 0;
279 	iec61883_plug_reg_lock_t pl;
280 	int		ph;
281 	av1394_pcr_t	*pcr;
282 
283 	if (ddi_copyin(arg, &pl, sizeof (pl), mode) != 0) {
284 		return (EFAULT);
285 	}
286 	ph = pl.pl_handle;
287 
288 	if (av1394_pcr_ph_is_remote(ph)) {
289 		ret = av1394_pcr_remote_cas(avp, ph,
290 		    &pl.pl_old, pl.pl_data, pl.pl_arg);
291 	} else {
292 		switch (av1394_pcr_ph2idx(ph)) {
293 		case AV1394_OMPR_IDX:
294 			ret = t1394_cmp_cas(avp->av_t1394_hdl, T1394_CMP_OMPR,
295 			    pl.pl_arg, pl.pl_data, &pl.pl_old);
296 			break;
297 		case AV1394_IMPR_IDX:
298 			ret = t1394_cmp_cas(avp->av_t1394_hdl, T1394_CMP_IMPR,
299 			    pl.pl_arg, pl.pl_data, &pl.pl_old);
300 			break;
301 		default:
302 			rw_enter(&cmp->cmp_pcr_rwlock, RW_WRITER);
303 			if ((pcr = av1394_pcr_ph2pcr(cmp, ph)) != NULL) {
304 				/* compare_swap */
305 				pl.pl_old = pcr->pcr_val;
306 				if (pcr->pcr_val == pl.pl_arg) {
307 					pcr->pcr_val = pl.pl_data;
308 				}
309 			} else {
310 				ret = EINVAL;
311 			}
312 			rw_exit(&cmp->cmp_pcr_rwlock);
313 		}
314 	}
315 
316 	if (ret == 0) {
317 		if (ddi_copyout(&pl, arg, sizeof (pl), mode) != 0) {
318 			ret = EFAULT;
319 		}
320 	}
321 
322 	return (ret);
323 }
324 
325 
326 /*
327  *
328  * --- configuration routines
329  *
330  */
331 static void
332 av1394_cmp_cleanup(av1394_inst_t *avp)
333 {
334 	av1394_cmp_t	*cmp = &avp->av_i.i_cmp;
335 	int		i;
336 
337 	rw_enter(&cmp->cmp_pcr_rwlock, RW_WRITER);
338 	for (i = 0; i < NELEM(cmp->cmp_pcr); i++) {
339 		if (cmp->cmp_pcr[i]) {
340 			av1394_pcr_fini(avp, i);
341 		}
342 	}
343 	rw_exit(&cmp->cmp_pcr_rwlock);
344 	rw_destroy(&cmp->cmp_pcr_rwlock);
345 	(void) t1394_cmp_unregister(avp->av_t1394_hdl);
346 }
347 
348 
349 /*
350  *
351  * --- ioctl routines
352  *
353  * IEC61883_PLUG_INIT for local plugs
354  */
355 static int
356 av1394_ioctl_plug_init_local(av1394_inst_t *avp, iec61883_plug_init_t *pip)
357 {
358 	av1394_cmp_t	*cmp = &avp->av_i.i_cmp;
359 	int		err;
360 	int		ph;		/* plug handle */
361 	int		idx, max_idx;	/* plug index */
362 
363 	/* MPR's are a special case */
364 	if ((pip->pi_type == IEC61883_PLUG_MASTER_IN) ||
365 	    (pip->pi_type == IEC61883_PLUG_MASTER_OUT)) {
366 		pip->pi_handle = av1394_pcr_make_ph(pip->pi_loc,
367 		    pip->pi_type, 0);
368 		return (0);
369 	}
370 
371 	/* PCR */
372 	rw_enter(&cmp->cmp_pcr_rwlock, RW_WRITER);
373 	if (pip->pi_num == IEC61883_PLUG_ANY) {
374 		if (pip->pi_type == IEC61883_PLUG_OUT) {
375 			idx = AV1394_OPCR0_IDX;
376 			max_idx = idx + AV1394_PCR_ADDR_NOPCR - 1;
377 		} else {
378 			ASSERT(pip->pi_type == IEC61883_PLUG_IN);
379 			idx = AV1394_IPCR0_IDX;
380 			max_idx = idx + AV1394_PCR_ADDR_NIPCR - 1;
381 		}
382 
383 		/* find unused PCR */
384 		for (; idx <= max_idx; idx++) {
385 			if (cmp->cmp_pcr[idx] != NULL) {
386 				continue;
387 			}
388 			err = av1394_pcr_init(avp, idx, AV1394_PCR_INIT_VAL);
389 			if (err == DDI_SUCCESS) {
390 				break;
391 			}
392 		}
393 	} else {
394 		ph = av1394_pcr_make_ph(pip->pi_loc, pip->pi_type, pip->pi_num);
395 		idx = max_idx = av1394_pcr_ph2idx(ph);
396 
397 		/* create PCR if not already */
398 		if (cmp->cmp_pcr[idx] == NULL) {
399 			err = av1394_pcr_init(avp, idx, AV1394_PCR_INIT_VAL);
400 		}
401 	}
402 
403 	rw_exit(&cmp->cmp_pcr_rwlock);
404 
405 	if ((err != DDI_SUCCESS) || (idx > max_idx)) {
406 		return (EBUSY);
407 	}
408 	pip->pi_rnum = av1394_pcr_idx2num(idx);
409 	pip->pi_handle = av1394_pcr_make_ph(pip->pi_loc, pip->pi_type,
410 	    pip->pi_rnum);
411 
412 	return (0);
413 }
414 
415 /*
416  * IEC61883_PLUG_INIT for remote plugs
417  */
418 static int
419 av1394_ioctl_plug_init_remote(av1394_inst_t *avp, iec61883_plug_init_t *pip)
420 {
421 	int		ph;
422 	uint32_t	val;
423 	int		ret;
424 
425 	if (pip->pi_num == IEC61883_PLUG_ANY) {
426 		return (EINVAL);
427 	}
428 
429 	ph = av1394_pcr_make_ph(pip->pi_loc, pip->pi_type, pip->pi_num);
430 
431 	/* check PCR existance by attempting to read it */
432 	if ((ret = av1394_pcr_remote_read(avp, ph, &val)) == 0) {
433 		pip->pi_handle = ph;
434 		pip->pi_rnum = pip->pi_num;
435 	}
436 
437 	return (ret);
438 }
439 
440 
441 /*
442  *
443  * --- plug routines
444  *
445  * initialize a PCR
446  */
447 static int
448 av1394_pcr_init(av1394_inst_t *avp, int idx, uint32_t val)
449 {
450 	av1394_cmp_t	*cmp = &avp->av_i.i_cmp;
451 	av1394_pcr_t	*pcr;
452 	uint64_t	addr;
453 	int		ret;
454 
455 	pcr = kmem_zalloc(sizeof (av1394_pcr_t), KM_SLEEP);
456 	pcr->pcr_val = val;
457 	cmp->cmp_pcr[idx] = pcr;
458 
459 	addr = av1394_pcr_idx2addr(idx);
460 	ret = av1394_pcr_alloc_addr(avp, addr, &pcr->pcr_addr_hdl);
461 	if (ret != DDI_SUCCESS) {
462 		kmem_free(pcr, sizeof (av1394_pcr_t));
463 		cmp->cmp_pcr[idx] = NULL;
464 	}
465 
466 	return (ret);
467 }
468 
469 /*
470  * finalize a PCR
471  */
472 static void
473 av1394_pcr_fini(av1394_inst_t *avp, int idx)
474 {
475 	av1394_cmp_t	*cmp = &avp->av_i.i_cmp;
476 
477 	av1394_pcr_free_addr(avp, &cmp->cmp_pcr[idx]->pcr_addr_hdl);
478 	kmem_free(cmp->cmp_pcr[idx], sizeof (av1394_pcr_t));
479 	cmp->cmp_pcr[idx] = NULL;
480 }
481 
482 /*
483  * allocate CSR address for a PCR
484  */
485 static int
486 av1394_pcr_alloc_addr(av1394_inst_t *avp, uint64_t addr,
487 		t1394_addr_handle_t *hdlp)
488 {
489 	t1394_alloc_addr_t aa;
490 	int		ret;
491 	int		result;
492 
493 	AV1394_TNF_ENTER(av1394_pcr_addr_alloc);
494 
495 	bzero(&aa, sizeof (aa));
496 	aa.aa_address = addr;
497 	aa.aa_length = 4;
498 	aa.aa_type = T1394_ADDR_FIXED;
499 	aa.aa_enable = T1394_ADDR_RDENBL | T1394_ADDR_LKENBL;
500 	aa.aa_evts.recv_read_request = av1394_pcr_recv_read_request;
501 	aa.aa_evts.recv_lock_request = av1394_pcr_recv_lock_request;
502 	aa.aa_arg = avp;
503 
504 	ret = t1394_alloc_addr(avp->av_t1394_hdl, &aa, 0, &result);
505 	if (ret != DDI_SUCCESS) {
506 		TNF_PROBE_2(av1394_pcr_alloc_addr_error, AV1394_TNF_CMP_ERROR,
507 		    "", tnf_int, ret, ret, tnf_int, result, result);
508 	} else {
509 		*hdlp = aa.aa_hdl;
510 	}
511 
512 	AV1394_TNF_EXIT(av1394_pcr_addr_alloc);
513 	return (ret);
514 }
515 
516 /*
517  * free CSR address occupied by a PCR
518  */
519 static void
520 av1394_pcr_free_addr(av1394_inst_t *avp, t1394_addr_handle_t *hdlp)
521 {
522 	int	ret;
523 
524 	ret = t1394_free_addr(avp->av_t1394_hdl, hdlp, 0);
525 	if (ret != DDI_SUCCESS) {
526 		TNF_PROBE_1(av1394_pcr_free_addr_error, AV1394_TNF_CMP_ERROR,
527 		    "", tnf_int, ret, ret);
528 	}
529 }
530 
531 /*
532  * make plug handle. range checking should be performed by caller
533  */
534 static int
535 av1394_pcr_make_ph(int loc, int type, int num)
536 {
537 	int	ph;
538 
539 	switch (type) {
540 	case IEC61883_PLUG_IN:
541 		ph = num + AV1394_IPCR0_IDX;
542 		break;
543 	case IEC61883_PLUG_OUT:
544 		ph = num + AV1394_OPCR0_IDX;
545 		break;
546 	case IEC61883_PLUG_MASTER_IN:
547 		ph = AV1394_IMPR_IDX;
548 		break;
549 	case IEC61883_PLUG_MASTER_OUT:
550 		ph = AV1394_OMPR_IDX;
551 		break;
552 	default:
553 		ASSERT(0);
554 	}
555 
556 	if (loc == IEC61883_LOC_REMOTE) {
557 		ph |= AV1394_PCR_REMOTE;
558 	}
559 
560 	return (ph);
561 }
562 
563 /*
564  * convert plug handle to PCR index
565  */
566 static int
567 av1394_pcr_ph2idx(int ph)
568 {
569 	return (ph & ~AV1394_PCR_REMOTE);
570 }
571 
572 /*
573  * convert plug handle to PCR pointer
574  */
575 static av1394_pcr_t *
576 av1394_pcr_ph2pcr(av1394_cmp_t *cmp, int ph)
577 {
578 	int	idx = av1394_pcr_ph2idx(ph);
579 
580 	if ((idx >= 0) && (idx < NELEM(cmp->cmp_pcr))) {
581 		return (cmp->cmp_pcr[idx]);
582 	} else {
583 		return (NULL);
584 	}
585 }
586 
587 /*
588  * convert PCR index to CSR address
589  */
590 static uint64_t
591 av1394_pcr_idx2addr(int idx)
592 {
593 	return (AV1394_PCR_ADDR_START + idx * 4);
594 }
595 
596 /*
597  * convert PCR index to number
598  */
599 static int
600 av1394_pcr_idx2num(int idx)
601 {
602 	ASSERT(!av1394_pcr_idx_is_mpr(idx));
603 
604 	return ((idx - 1) % 32);
605 }
606 
607 /*
608  * returns B_TRUE if a master plug
609  */
610 static boolean_t
611 av1394_pcr_idx_is_mpr(int idx)
612 {
613 	return (idx % 32 == 0);
614 }
615 
616 static boolean_t
617 av1394_pcr_ph_is_mpr(int ph)
618 {
619 	return (av1394_pcr_ph2idx(ph) % 32 == 0);
620 }
621 
622 /*
623  * returns B_TRUE if a remote plug
624  */
625 static boolean_t
626 av1394_pcr_ph_is_remote(int ph)
627 {
628 	return ((ph & AV1394_PCR_REMOTE) != 0);
629 }
630 
631 
632 /*
633  *
634  * --- callbacks
635  *
636  */
637 static void
638 av1394_pcr_recv_read_request(cmd1394_cmd_t *req)
639 {
640 	av1394_inst_t	*avp = req->cmd_callback_arg;
641 	av1394_cmp_t	*cmp = &avp->av_i.i_cmp;
642 	int		idx;	/* PCR index */
643 	av1394_pcr_t	*pcr;
644 	int		err;
645 
646 	AV1394_TNF_ENTER(av1394_pcr_recv_read_request);
647 
648 	idx = (req->cmd_addr - AV1394_PCR_ADDR_START) / 4;
649 
650 	if (req->cmd_type != CMD1394_ASYNCH_RD_QUAD) {
651 		req->cmd_result = IEEE1394_RESP_TYPE_ERROR;
652 	} else if ((idx >= NELEM(cmp->cmp_pcr)) ||
653 	    ((pcr = cmp->cmp_pcr[idx]) == NULL)) {
654 		req->cmd_result = IEEE1394_RESP_ADDRESS_ERROR;
655 	} else {
656 		/* read */
657 		rw_enter(&cmp->cmp_pcr_rwlock, RW_READER);
658 		req->cmd_u.q.quadlet_data = pcr->pcr_val;
659 		rw_exit(&cmp->cmp_pcr_rwlock);
660 
661 		req->cmd_result = IEEE1394_RESP_COMPLETE;
662 	}
663 
664 	err = t1394_recv_request_done(avp->av_t1394_hdl, req, 0);
665 	if (err != DDI_SUCCESS) {
666 		TNF_PROBE_1(av1394_pcr_recv_read_request_done_error,
667 		    AV1394_TNF_CMP_ERROR, "", tnf_int, err, err);
668 	}
669 
670 	AV1394_TNF_EXIT(av1394_pcr_recv_read_request);
671 }
672 
673 static void
674 av1394_pcr_recv_lock_request(cmd1394_cmd_t *req)
675 {
676 	av1394_inst_t	*avp = req->cmd_callback_arg;
677 	av1394_cmp_t	*cmp = &avp->av_i.i_cmp;
678 	int		idx;	/* PCR index */
679 	av1394_pcr_t	*pcr;
680 	int		err;
681 
682 	AV1394_TNF_ENTER(av1394_pcr_recv_lock_request);
683 
684 	idx = (req->cmd_addr - AV1394_PCR_ADDR_START) / 4;
685 
686 	if ((req->cmd_type != CMD1394_ASYNCH_LOCK_32) ||
687 	    (req->cmd_u.l32.lock_type != CMD1394_LOCK_COMPARE_SWAP)) {
688 		req->cmd_result = IEEE1394_RESP_TYPE_ERROR;
689 	} else if ((idx >= NELEM(cmp->cmp_pcr)) ||
690 	    ((pcr = cmp->cmp_pcr[idx]) == NULL)) {
691 		req->cmd_result = IEEE1394_RESP_ADDRESS_ERROR;
692 	} else {
693 		/* compare_swap */
694 		rw_enter(&cmp->cmp_pcr_rwlock, RW_WRITER);
695 		if (pcr->pcr_val == req->cmd_u.l32.arg_value) {
696 			pcr->pcr_val = req->cmd_u.l32.data_value;
697 		}
698 		req->cmd_u.l32.old_value = pcr->pcr_val;
699 		rw_exit(&cmp->cmp_pcr_rwlock);
700 
701 		req->cmd_result = IEEE1394_RESP_COMPLETE;
702 	}
703 
704 	err = t1394_recv_request_done(avp->av_t1394_hdl, req, 0);
705 	if (err != DDI_SUCCESS) {
706 		TNF_PROBE_2(av1394_pcr_recv_lock_request_done_error,
707 		    AV1394_TNF_CMP_ERROR, "", tnf_int, err, err,
708 		    tnf_int, result, req->cmd_result);
709 	}
710 
711 	AV1394_TNF_EXIT(av1394_pcr_recv_lock_request);
712 }
713 
714 
715 /*
716  *
717  * --- remote PCR routines
718  *
719  * read specified PCR on the remote node
720  */
721 static int
722 av1394_pcr_remote_read(av1394_inst_t *avp, int ph, uint32_t *valp)
723 {
724 	cmd1394_cmd_t	*cmd;
725 	int		ret = 0;
726 	int		err;
727 
728 	ret = t1394_alloc_cmd(avp->av_t1394_hdl, 0, &cmd);
729 	if (ret != DDI_SUCCESS) {
730 		return (ENOMEM);
731 	}
732 
733 	cmd->cmd_addr = av1394_pcr_idx2addr(av1394_pcr_ph2idx(ph));
734 	cmd->cmd_type = CMD1394_ASYNCH_RD_QUAD;
735 	cmd->cmd_options = CMD1394_BLOCKING;
736 
737 	if (((err = t1394_read(avp->av_t1394_hdl, cmd)) == DDI_SUCCESS) &&
738 	    (cmd->cmd_result == CMD1394_CMDSUCCESS)) {
739 		*valp = cmd->cmd_u.q.quadlet_data;
740 	} else {
741 		TNF_PROBE_2(av1394_pcr_remote_read_error, AV1394_TNF_CMP_ERROR,
742 		    "", tnf_int, err, err, tnf_int, result, cmd->cmd_result);
743 		ret = EIO;
744 	}
745 
746 	err = t1394_free_cmd(avp->av_t1394_hdl, 0, &cmd);
747 	ASSERT(err == DDI_SUCCESS);
748 
749 	return (ret);
750 }
751 
752 /*
753  * compare_swap specified PCR on the remote node
754  */
755 static int
756 av1394_pcr_remote_cas(av1394_inst_t *avp, int ph, uint32_t *old_valuep,
757 		uint32_t data_value, uint32_t arg_value)
758 {
759 	cmd1394_cmd_t	*cmd;
760 	int		ret = 0;
761 	int		err;
762 
763 	ret = t1394_alloc_cmd(avp->av_t1394_hdl, 0, &cmd);
764 	if (ret != DDI_SUCCESS) {
765 		return (ENOMEM);
766 	}
767 
768 	cmd->cmd_addr = av1394_pcr_idx2addr(av1394_pcr_ph2idx(ph));
769 	cmd->cmd_type = CMD1394_ASYNCH_LOCK_32;
770 	cmd->cmd_u.l32.lock_type = CMD1394_LOCK_COMPARE_SWAP;
771 	cmd->cmd_u.l32.data_value = data_value;
772 	cmd->cmd_u.l32.arg_value = arg_value;
773 	cmd->cmd_u.l32.num_retries = 0;
774 	cmd->cmd_options = CMD1394_BLOCKING;
775 
776 	if (((err = t1394_lock(avp->av_t1394_hdl, cmd)) == DDI_SUCCESS) &&
777 	    (cmd->cmd_result == CMD1394_CMDSUCCESS)) {
778 		*old_valuep = cmd->cmd_u.l32.old_value;
779 	} else {
780 		TNF_PROBE_2(av1394_pcr_remote_cas_error, AV1394_TNF_CMP_ERROR,
781 		    "", tnf_int, err, err, tnf_int, result, cmd->cmd_result);
782 		ret = EIO;
783 	}
784 
785 	err = t1394_free_cmd(avp->av_t1394_hdl, 0, &cmd);
786 	ASSERT(err == DDI_SUCCESS);
787 
788 	return (ret);
789 }
790