17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate  * CDDL HEADER START
37c478bd9Sstevel@tonic-gate  *
47c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
547cd5876SAlan Perry  * Common Development and Distribution License (the "License").
647cd5876SAlan Perry  * You may not use this file except in compliance with the License.
77c478bd9Sstevel@tonic-gate  *
87c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
97c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
107c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
117c478bd9Sstevel@tonic-gate  * and limitations under the License.
127c478bd9Sstevel@tonic-gate  *
137c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
147c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
157c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
167c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
177c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
187c478bd9Sstevel@tonic-gate  *
197c478bd9Sstevel@tonic-gate  * CDDL HEADER END
207c478bd9Sstevel@tonic-gate  */
217c478bd9Sstevel@tonic-gate /*
2247cd5876SAlan Perry  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
237c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
247c478bd9Sstevel@tonic-gate  */
257c478bd9Sstevel@tonic-gate 
267c478bd9Sstevel@tonic-gate /*
277c478bd9Sstevel@tonic-gate  * av1394 CMP (Connection Management Procedures)
287c478bd9Sstevel@tonic-gate  */
297c478bd9Sstevel@tonic-gate #include <sys/1394/targets/av1394/av1394_impl.h>
307c478bd9Sstevel@tonic-gate 
317c478bd9Sstevel@tonic-gate /* configuration routines */
327c478bd9Sstevel@tonic-gate static void	av1394_cmp_cleanup(av1394_inst_t *icp);
337c478bd9Sstevel@tonic-gate 
347c478bd9Sstevel@tonic-gate /* ioctl routines */
357c478bd9Sstevel@tonic-gate static int	av1394_ioctl_plug_init_local(av1394_inst_t *,
367c478bd9Sstevel@tonic-gate 		iec61883_plug_init_t *);
377c478bd9Sstevel@tonic-gate static int	av1394_ioctl_plug_init_remote(av1394_inst_t *,
387c478bd9Sstevel@tonic-gate 		iec61883_plug_init_t *);
397c478bd9Sstevel@tonic-gate 
407c478bd9Sstevel@tonic-gate /* local PCR routines */
417c478bd9Sstevel@tonic-gate static int	av1394_pcr_init(av1394_inst_t *, int, uint32_t);
427c478bd9Sstevel@tonic-gate static void	av1394_pcr_fini(av1394_inst_t *, int);
437c478bd9Sstevel@tonic-gate static int	av1394_pcr_alloc_addr(av1394_inst_t *, uint64_t,
447c478bd9Sstevel@tonic-gate 		t1394_addr_handle_t *);
457c478bd9Sstevel@tonic-gate static void	av1394_pcr_free_addr(av1394_inst_t *, t1394_addr_handle_t *);
467c478bd9Sstevel@tonic-gate static int	av1394_pcr_make_ph(int, int, int);
477c478bd9Sstevel@tonic-gate static int	av1394_pcr_ph2idx(int);
487c478bd9Sstevel@tonic-gate static av1394_pcr_t *av1394_pcr_ph2pcr(av1394_cmp_t *, int);
497c478bd9Sstevel@tonic-gate static uint64_t	av1394_pcr_idx2addr(int);
507c478bd9Sstevel@tonic-gate static int	av1394_pcr_idx2num(int);
517c478bd9Sstevel@tonic-gate static boolean_t av1394_pcr_idx_is_mpr(int);
527c478bd9Sstevel@tonic-gate static boolean_t av1394_pcr_ph_is_mpr(int);
537c478bd9Sstevel@tonic-gate static boolean_t av1394_pcr_ph_is_remote(int);
547c478bd9Sstevel@tonic-gate 
557c478bd9Sstevel@tonic-gate /* callbacks */
567c478bd9Sstevel@tonic-gate static void	av1394_pcr_recv_read_request(cmd1394_cmd_t *);
577c478bd9Sstevel@tonic-gate static void	av1394_pcr_recv_lock_request(cmd1394_cmd_t *);
587c478bd9Sstevel@tonic-gate 
597c478bd9Sstevel@tonic-gate /* remote PCR routines */
607c478bd9Sstevel@tonic-gate static int	av1394_pcr_remote_read(av1394_inst_t *, int, uint32_t *);
617c478bd9Sstevel@tonic-gate static int	av1394_pcr_remote_cas(av1394_inst_t *, int, uint32_t *,
627c478bd9Sstevel@tonic-gate 		uint32_t, uint32_t);
637c478bd9Sstevel@tonic-gate 
647c478bd9Sstevel@tonic-gate int
av1394_cmp_init(av1394_inst_t * avp)657c478bd9Sstevel@tonic-gate av1394_cmp_init(av1394_inst_t *avp)
667c478bd9Sstevel@tonic-gate {
677c478bd9Sstevel@tonic-gate 	av1394_cmp_t	*cmp = &avp->av_i.i_cmp;
687c478bd9Sstevel@tonic-gate 	ddi_iblock_cookie_t ibc = avp->av_attachinfo.iblock_cookie;
697c478bd9Sstevel@tonic-gate 	int		ret;
707c478bd9Sstevel@tonic-gate 
717c478bd9Sstevel@tonic-gate 	ret = t1394_cmp_register(avp->av_t1394_hdl, NULL, 0);
727c478bd9Sstevel@tonic-gate 
737c478bd9Sstevel@tonic-gate 	if (ret == DDI_SUCCESS) {
747c478bd9Sstevel@tonic-gate 		rw_init(&cmp->cmp_pcr_rwlock, NULL, RW_DRIVER, ibc);
757c478bd9Sstevel@tonic-gate 	}
767c478bd9Sstevel@tonic-gate 
777c478bd9Sstevel@tonic-gate 	return (ret);
787c478bd9Sstevel@tonic-gate }
797c478bd9Sstevel@tonic-gate 
807c478bd9Sstevel@tonic-gate void
av1394_cmp_fini(av1394_inst_t * avp)817c478bd9Sstevel@tonic-gate av1394_cmp_fini(av1394_inst_t *avp)
827c478bd9Sstevel@tonic-gate {
837c478bd9Sstevel@tonic-gate 	av1394_cmp_cleanup(avp);
847c478bd9Sstevel@tonic-gate }
857c478bd9Sstevel@tonic-gate 
867c478bd9Sstevel@tonic-gate void
av1394_cmp_bus_reset(av1394_inst_t * avp)877c478bd9Sstevel@tonic-gate av1394_cmp_bus_reset(av1394_inst_t *avp)
887c478bd9Sstevel@tonic-gate {
897c478bd9Sstevel@tonic-gate 	av1394_cmp_t	*cmp = &avp->av_i.i_cmp;
907c478bd9Sstevel@tonic-gate 	int		i;
917c478bd9Sstevel@tonic-gate 
927c478bd9Sstevel@tonic-gate 	/* reset PCR values */
937c478bd9Sstevel@tonic-gate 	rw_enter(&cmp->cmp_pcr_rwlock, RW_WRITER);
947c478bd9Sstevel@tonic-gate 	for (i = 0; i < NELEM(cmp->cmp_pcr); i++) {
957c478bd9Sstevel@tonic-gate 		if ((i == AV1394_OMPR_IDX) || (i == AV1394_IMPR_IDX)) {
967c478bd9Sstevel@tonic-gate 			continue;
977c478bd9Sstevel@tonic-gate 		}
987c478bd9Sstevel@tonic-gate 		if (cmp->cmp_pcr[i]) {
997c478bd9Sstevel@tonic-gate 			if (i < AV1394_IMPR_IDX) {
1007c478bd9Sstevel@tonic-gate 				cmp->cmp_pcr[i]->pcr_val &=
10147cd5876SAlan Perry 				    ~AV1394_OPCR_BR_CLEAR_MASK;
1027c478bd9Sstevel@tonic-gate 			} else {
1037c478bd9Sstevel@tonic-gate 				cmp->cmp_pcr[i]->pcr_val &=
10447cd5876SAlan Perry 				    ~AV1394_IPCR_BR_CLEAR_MASK;
1057c478bd9Sstevel@tonic-gate 			}
1067c478bd9Sstevel@tonic-gate 		}
1077c478bd9Sstevel@tonic-gate 	}
1087c478bd9Sstevel@tonic-gate 	rw_exit(&cmp->cmp_pcr_rwlock);
1097c478bd9Sstevel@tonic-gate }
1107c478bd9Sstevel@tonic-gate 
1117c478bd9Sstevel@tonic-gate /*
1127c478bd9Sstevel@tonic-gate  * on close, free iPCRs and oPCRs not finalized by application
1137c478bd9Sstevel@tonic-gate  */
1147c478bd9Sstevel@tonic-gate void
av1394_cmp_close(av1394_inst_t * avp)1157c478bd9Sstevel@tonic-gate av1394_cmp_close(av1394_inst_t *avp)
1167c478bd9Sstevel@tonic-gate {
1177c478bd9Sstevel@tonic-gate 	av1394_cmp_t	*cmp = &avp->av_i.i_cmp;
1187c478bd9Sstevel@tonic-gate 	int		i;
1197c478bd9Sstevel@tonic-gate 
1207c478bd9Sstevel@tonic-gate 	rw_enter(&cmp->cmp_pcr_rwlock, RW_WRITER);
1217c478bd9Sstevel@tonic-gate 	for (i = 0; i < NELEM(cmp->cmp_pcr); i++) {
1227c478bd9Sstevel@tonic-gate 		if ((i == AV1394_OMPR_IDX) || (i == AV1394_IMPR_IDX)) {
1237c478bd9Sstevel@tonic-gate 			continue;
1247c478bd9Sstevel@tonic-gate 		}
1257c478bd9Sstevel@tonic-gate 		if (cmp->cmp_pcr[i]) {
1267c478bd9Sstevel@tonic-gate 			av1394_pcr_fini(avp, i);
1277c478bd9Sstevel@tonic-gate 		}
1287c478bd9Sstevel@tonic-gate 	}
1297c478bd9Sstevel@tonic-gate 	rw_exit(&cmp->cmp_pcr_rwlock);
1307c478bd9Sstevel@tonic-gate }
1317c478bd9Sstevel@tonic-gate 
1327c478bd9Sstevel@tonic-gate /*
1337c478bd9Sstevel@tonic-gate  *
1347c478bd9Sstevel@tonic-gate  * --- ioctls
1357c478bd9Sstevel@tonic-gate  *
1367c478bd9Sstevel@tonic-gate  * IEC61883_PLUG_INIT
1377c478bd9Sstevel@tonic-gate  */
1387c478bd9Sstevel@tonic-gate int
av1394_ioctl_plug_init(av1394_inst_t * avp,void * arg,int mode)1397c478bd9Sstevel@tonic-gate av1394_ioctl_plug_init(av1394_inst_t *avp, void *arg, int mode)
1407c478bd9Sstevel@tonic-gate {
1417c478bd9Sstevel@tonic-gate 	int		ret = 0;
1427c478bd9Sstevel@tonic-gate 	iec61883_plug_init_t pi;
1437c478bd9Sstevel@tonic-gate 
1447c478bd9Sstevel@tonic-gate 	if (ddi_copyin(arg, &pi, sizeof (pi), mode) != 0) {
1457c478bd9Sstevel@tonic-gate 		return (EFAULT);
1467c478bd9Sstevel@tonic-gate 	}
1477c478bd9Sstevel@tonic-gate 
1487c478bd9Sstevel@tonic-gate 	/* check arguments */
1497c478bd9Sstevel@tonic-gate 	if (((pi.pi_type != IEC61883_PLUG_IN) &&
1507c478bd9Sstevel@tonic-gate 	    (pi.pi_type != IEC61883_PLUG_OUT) &&
1517c478bd9Sstevel@tonic-gate 	    (pi.pi_type != IEC61883_PLUG_MASTER_IN) &&
1527c478bd9Sstevel@tonic-gate 	    (pi.pi_type != IEC61883_PLUG_MASTER_OUT)) ||
1537c478bd9Sstevel@tonic-gate 	    (((pi.pi_num < 0) || (pi.pi_num >= AV1394_NPCR)) &&
1547c478bd9Sstevel@tonic-gate 	    (pi.pi_num != IEC61883_PLUG_ANY))) {
1557c478bd9Sstevel@tonic-gate 		return (EINVAL);
1567c478bd9Sstevel@tonic-gate 	}
1577c478bd9Sstevel@tonic-gate 
1587c478bd9Sstevel@tonic-gate 	if (pi.pi_loc == IEC61883_LOC_LOCAL) {
1597c478bd9Sstevel@tonic-gate 		ret = av1394_ioctl_plug_init_local(avp, &pi);
1607c478bd9Sstevel@tonic-gate 	} else if (pi.pi_loc == IEC61883_LOC_REMOTE) {
1617c478bd9Sstevel@tonic-gate 		ret = av1394_ioctl_plug_init_remote(avp, &pi);
1627c478bd9Sstevel@tonic-gate 	} else {
1637c478bd9Sstevel@tonic-gate 		ret = EINVAL;
1647c478bd9Sstevel@tonic-gate 	}
1657c478bd9Sstevel@tonic-gate 
1667c478bd9Sstevel@tonic-gate 	if (ret == 0) {
1677c478bd9Sstevel@tonic-gate 		if (ddi_copyout(&pi, arg, sizeof (pi), mode) != 0) {
1687c478bd9Sstevel@tonic-gate 			ret = EFAULT;
1697c478bd9Sstevel@tonic-gate 		}
1707c478bd9Sstevel@tonic-gate 	}
1717c478bd9Sstevel@tonic-gate 
1727c478bd9Sstevel@tonic-gate 	return (ret);
1737c478bd9Sstevel@tonic-gate }
1747c478bd9Sstevel@tonic-gate 
1757c478bd9Sstevel@tonic-gate /*
1767c478bd9Sstevel@tonic-gate  * IEC61883_PLUG_FINI
1777c478bd9Sstevel@tonic-gate  */
1787c478bd9Sstevel@tonic-gate /*ARGSUSED*/
1797c478bd9Sstevel@tonic-gate int
av1394_ioctl_plug_fini(av1394_inst_t * avp,void * arg,int mode)1807c478bd9Sstevel@tonic-gate av1394_ioctl_plug_fini(av1394_inst_t *avp, void *arg, int mode)
1817c478bd9Sstevel@tonic-gate {
1827c478bd9Sstevel@tonic-gate 	av1394_cmp_t	*cmp = &avp->av_i.i_cmp;
1837c478bd9Sstevel@tonic-gate 	int		ret;
1847c478bd9Sstevel@tonic-gate 	int		ph;
1857c478bd9Sstevel@tonic-gate 
1867c478bd9Sstevel@tonic-gate 	ph = (int)(intptr_t)arg;
1877c478bd9Sstevel@tonic-gate 
1887c478bd9Sstevel@tonic-gate 	if (av1394_pcr_ph_is_remote(ph) || av1394_pcr_ph_is_mpr(ph)) {
1897c478bd9Sstevel@tonic-gate 		return (0);
1907c478bd9Sstevel@tonic-gate 	}
1917c478bd9Sstevel@tonic-gate 
1927c478bd9Sstevel@tonic-gate 	rw_enter(&cmp->cmp_pcr_rwlock, RW_WRITER);
1937c478bd9Sstevel@tonic-gate 	if (av1394_pcr_ph2pcr(cmp, ph) != NULL) {
1947c478bd9Sstevel@tonic-gate 		av1394_pcr_fini(avp, av1394_pcr_ph2idx(ph));
1957c478bd9Sstevel@tonic-gate 		ret = 0;
1967c478bd9Sstevel@tonic-gate 	} else {
1977c478bd9Sstevel@tonic-gate 		ret = EINVAL;
1987c478bd9Sstevel@tonic-gate 	}
1997c478bd9Sstevel@tonic-gate 	rw_exit(&cmp->cmp_pcr_rwlock);
2007c478bd9Sstevel@tonic-gate 
2017c478bd9Sstevel@tonic-gate 	return (ret);
2027c478bd9Sstevel@tonic-gate }
2037c478bd9Sstevel@tonic-gate 
2047c478bd9Sstevel@tonic-gate /*
2057c478bd9Sstevel@tonic-gate  * IEC61883_PLUG_REG_READ
2067c478bd9Sstevel@tonic-gate  */
2077c478bd9Sstevel@tonic-gate int
av1394_ioctl_plug_reg_read(av1394_inst_t * avp,void * arg,int mode)2087c478bd9Sstevel@tonic-gate av1394_ioctl_plug_reg_read(av1394_inst_t *avp, void *arg, int mode)
2097c478bd9Sstevel@tonic-gate {
2107c478bd9Sstevel@tonic-gate 	av1394_cmp_t	*cmp = &avp->av_i.i_cmp;
2117c478bd9Sstevel@tonic-gate 	int		ret = 0;
2127c478bd9Sstevel@tonic-gate 	iec61883_plug_reg_val_t pr;
2137c478bd9Sstevel@tonic-gate 	int		ph;
2147c478bd9Sstevel@tonic-gate 	av1394_pcr_t	*pcr;
2157c478bd9Sstevel@tonic-gate 
2167c478bd9Sstevel@tonic-gate 	if (ddi_copyin(arg, &pr, sizeof (pr), mode) != 0) {
2177c478bd9Sstevel@tonic-gate 		return (EFAULT);
2187c478bd9Sstevel@tonic-gate 	}
2197c478bd9Sstevel@tonic-gate 	ph = pr.pr_handle;
2207c478bd9Sstevel@tonic-gate 
2217c478bd9Sstevel@tonic-gate 	if (av1394_pcr_ph_is_remote(ph)) {
2227c478bd9Sstevel@tonic-gate 		ret = av1394_pcr_remote_read(avp, ph, &pr.pr_val);
2237c478bd9Sstevel@tonic-gate 	} else {
2247c478bd9Sstevel@tonic-gate 		switch (av1394_pcr_ph2idx(ph)) {
2257c478bd9Sstevel@tonic-gate 		case AV1394_OMPR_IDX:
2267c478bd9Sstevel@tonic-gate 			ret = t1394_cmp_read(avp->av_t1394_hdl, T1394_CMP_OMPR,
22747cd5876SAlan Perry 			    &pr.pr_val);
2287c478bd9Sstevel@tonic-gate 			break;
2297c478bd9Sstevel@tonic-gate 		case AV1394_IMPR_IDX:
2307c478bd9Sstevel@tonic-gate 			ret = t1394_cmp_read(avp->av_t1394_hdl, T1394_CMP_IMPR,
23147cd5876SAlan Perry 			    &pr.pr_val);
2327c478bd9Sstevel@tonic-gate 			break;
2337c478bd9Sstevel@tonic-gate 		default:
2347c478bd9Sstevel@tonic-gate 			rw_enter(&cmp->cmp_pcr_rwlock, RW_READER);
2357c478bd9Sstevel@tonic-gate 			if ((pcr = av1394_pcr_ph2pcr(cmp, ph)) != NULL) {
2367c478bd9Sstevel@tonic-gate 				pr.pr_val = pcr->pcr_val;
2377c478bd9Sstevel@tonic-gate 			} else {
2387c478bd9Sstevel@tonic-gate 				ret = EINVAL;
2397c478bd9Sstevel@tonic-gate 			}
2407c478bd9Sstevel@tonic-gate 			rw_exit(&cmp->cmp_pcr_rwlock);
2417c478bd9Sstevel@tonic-gate 		}
2427c478bd9Sstevel@tonic-gate 	}
2437c478bd9Sstevel@tonic-gate 
2447c478bd9Sstevel@tonic-gate 	if (ret == 0) {
2457c478bd9Sstevel@tonic-gate 		if (ddi_copyout(&pr, arg, sizeof (pr), mode) != 0) {
2467c478bd9Sstevel@tonic-gate 			ret = EFAULT;
2477c478bd9Sstevel@tonic-gate 		}
2487c478bd9Sstevel@tonic-gate 	}
2497c478bd9Sstevel@tonic-gate 
2507c478bd9Sstevel@tonic-gate 	return (ret);
2517c478bd9Sstevel@tonic-gate }
2527c478bd9Sstevel@tonic-gate 
2537c478bd9Sstevel@tonic-gate /*
2547c478bd9Sstevel@tonic-gate  * IEC61883_PLUG_REG_CAS
2557c478bd9Sstevel@tonic-gate  */
2567c478bd9Sstevel@tonic-gate int
av1394_ioctl_plug_reg_cas(av1394_inst_t * avp,void * arg,int mode)2577c478bd9Sstevel@tonic-gate av1394_ioctl_plug_reg_cas(av1394_inst_t *avp, void *arg, int mode)
2587c478bd9Sstevel@tonic-gate {
2597c478bd9Sstevel@tonic-gate 	av1394_cmp_t	*cmp = &avp->av_i.i_cmp;
2607c478bd9Sstevel@tonic-gate 	int		ret = 0;
2617c478bd9Sstevel@tonic-gate 	iec61883_plug_reg_lock_t pl;
2627c478bd9Sstevel@tonic-gate 	int		ph;
2637c478bd9Sstevel@tonic-gate 	av1394_pcr_t	*pcr;
2647c478bd9Sstevel@tonic-gate 
2657c478bd9Sstevel@tonic-gate 	if (ddi_copyin(arg, &pl, sizeof (pl), mode) != 0) {
2667c478bd9Sstevel@tonic-gate 		return (EFAULT);
2677c478bd9Sstevel@tonic-gate 	}
2687c478bd9Sstevel@tonic-gate 	ph = pl.pl_handle;
2697c478bd9Sstevel@tonic-gate 
2707c478bd9Sstevel@tonic-gate 	if (av1394_pcr_ph_is_remote(ph)) {
2717c478bd9Sstevel@tonic-gate 		ret = av1394_pcr_remote_cas(avp, ph,
27247cd5876SAlan Perry 		    &pl.pl_old, pl.pl_data, pl.pl_arg);
2737c478bd9Sstevel@tonic-gate 	} else {
2747c478bd9Sstevel@tonic-gate 		switch (av1394_pcr_ph2idx(ph)) {
2757c478bd9Sstevel@tonic-gate 		case AV1394_OMPR_IDX:
2767c478bd9Sstevel@tonic-gate 			ret = t1394_cmp_cas(avp->av_t1394_hdl, T1394_CMP_OMPR,
27747cd5876SAlan Perry 			    pl.pl_arg, pl.pl_data, &pl.pl_old);
2787c478bd9Sstevel@tonic-gate 			break;
2797c478bd9Sstevel@tonic-gate 		case AV1394_IMPR_IDX:
2807c478bd9Sstevel@tonic-gate 			ret = t1394_cmp_cas(avp->av_t1394_hdl, T1394_CMP_IMPR,
28147cd5876SAlan Perry 			    pl.pl_arg, pl.pl_data, &pl.pl_old);
2827c478bd9Sstevel@tonic-gate 			break;
2837c478bd9Sstevel@tonic-gate 		default:
2847c478bd9Sstevel@tonic-gate 			rw_enter(&cmp->cmp_pcr_rwlock, RW_WRITER);
2857c478bd9Sstevel@tonic-gate 			if ((pcr = av1394_pcr_ph2pcr(cmp, ph)) != NULL) {
2867c478bd9Sstevel@tonic-gate 				/* compare_swap */
2877c478bd9Sstevel@tonic-gate 				pl.pl_old = pcr->pcr_val;
2887c478bd9Sstevel@tonic-gate 				if (pcr->pcr_val == pl.pl_arg) {
2897c478bd9Sstevel@tonic-gate 					pcr->pcr_val = pl.pl_data;
2907c478bd9Sstevel@tonic-gate 				}
2917c478bd9Sstevel@tonic-gate 			} else {
2927c478bd9Sstevel@tonic-gate 				ret = EINVAL;
2937c478bd9Sstevel@tonic-gate 			}
2947c478bd9Sstevel@tonic-gate 			rw_exit(&cmp->cmp_pcr_rwlock);
2957c478bd9Sstevel@tonic-gate 		}
2967c478bd9Sstevel@tonic-gate 	}
2977c478bd9Sstevel@tonic-gate 
2987c478bd9Sstevel@tonic-gate 	if (ret == 0) {
2997c478bd9Sstevel@tonic-gate 		if (ddi_copyout(&pl, arg, sizeof (pl), mode) != 0) {
3007c478bd9Sstevel@tonic-gate 			ret = EFAULT;
3017c478bd9Sstevel@tonic-gate 		}
3027c478bd9Sstevel@tonic-gate 	}
3037c478bd9Sstevel@tonic-gate 
3047c478bd9Sstevel@tonic-gate 	return (ret);
3057c478bd9Sstevel@tonic-gate }
3067c478bd9Sstevel@tonic-gate 
3077c478bd9Sstevel@tonic-gate 
3087c478bd9Sstevel@tonic-gate /*
3097c478bd9Sstevel@tonic-gate  *
3107c478bd9Sstevel@tonic-gate  * --- configuration routines
3117c478bd9Sstevel@tonic-gate  *
3127c478bd9Sstevel@tonic-gate  */
3137c478bd9Sstevel@tonic-gate static void
av1394_cmp_cleanup(av1394_inst_t * avp)3147c478bd9Sstevel@tonic-gate av1394_cmp_cleanup(av1394_inst_t *avp)
3157c478bd9Sstevel@tonic-gate {
3167c478bd9Sstevel@tonic-gate 	av1394_cmp_t	*cmp = &avp->av_i.i_cmp;
3177c478bd9Sstevel@tonic-gate 	int		i;
3187c478bd9Sstevel@tonic-gate 
3197c478bd9Sstevel@tonic-gate 	rw_enter(&cmp->cmp_pcr_rwlock, RW_WRITER);
3207c478bd9Sstevel@tonic-gate 	for (i = 0; i < NELEM(cmp->cmp_pcr); i++) {
3217c478bd9Sstevel@tonic-gate 		if (cmp->cmp_pcr[i]) {
3227c478bd9Sstevel@tonic-gate 			av1394_pcr_fini(avp, i);
3237c478bd9Sstevel@tonic-gate 		}
3247c478bd9Sstevel@tonic-gate 	}
3257c478bd9Sstevel@tonic-gate 	rw_exit(&cmp->cmp_pcr_rwlock);
3267c478bd9Sstevel@tonic-gate 	rw_destroy(&cmp->cmp_pcr_rwlock);
3277c478bd9Sstevel@tonic-gate 	(void) t1394_cmp_unregister(avp->av_t1394_hdl);
3287c478bd9Sstevel@tonic-gate }
3297c478bd9Sstevel@tonic-gate 
3307c478bd9Sstevel@tonic-gate 
3317c478bd9Sstevel@tonic-gate /*
3327c478bd9Sstevel@tonic-gate  *
3337c478bd9Sstevel@tonic-gate  * --- ioctl routines
3347c478bd9Sstevel@tonic-gate  *
3357c478bd9Sstevel@tonic-gate  * IEC61883_PLUG_INIT for local plugs
3367c478bd9Sstevel@tonic-gate  */
3377c478bd9Sstevel@tonic-gate static int
av1394_ioctl_plug_init_local(av1394_inst_t * avp,iec61883_plug_init_t * pip)3387c478bd9Sstevel@tonic-gate av1394_ioctl_plug_init_local(av1394_inst_t *avp, iec61883_plug_init_t *pip)
3397c478bd9Sstevel@tonic-gate {
3407c478bd9Sstevel@tonic-gate 	av1394_cmp_t	*cmp = &avp->av_i.i_cmp;
3417c478bd9Sstevel@tonic-gate 	int		err;
3427c478bd9Sstevel@tonic-gate 	int		ph;		/* plug handle */
3437c478bd9Sstevel@tonic-gate 	int		idx, max_idx;	/* plug index */
3447c478bd9Sstevel@tonic-gate 
3457c478bd9Sstevel@tonic-gate 	/* MPR's are a special case */
3467c478bd9Sstevel@tonic-gate 	if ((pip->pi_type == IEC61883_PLUG_MASTER_IN) ||
3477c478bd9Sstevel@tonic-gate 	    (pip->pi_type == IEC61883_PLUG_MASTER_OUT)) {
3487c478bd9Sstevel@tonic-gate 		pip->pi_handle = av1394_pcr_make_ph(pip->pi_loc,
34947cd5876SAlan Perry 		    pip->pi_type, 0);
3507c478bd9Sstevel@tonic-gate 		return (0);
3517c478bd9Sstevel@tonic-gate 	}
3527c478bd9Sstevel@tonic-gate 
3537c478bd9Sstevel@tonic-gate 	/* PCR */
3547c478bd9Sstevel@tonic-gate 	rw_enter(&cmp->cmp_pcr_rwlock, RW_WRITER);
3557c478bd9Sstevel@tonic-gate 	if (pip->pi_num == IEC61883_PLUG_ANY) {
3567c478bd9Sstevel@tonic-gate 		if (pip->pi_type == IEC61883_PLUG_OUT) {
3577c478bd9Sstevel@tonic-gate 			idx = AV1394_OPCR0_IDX;
3587c478bd9Sstevel@tonic-gate 			max_idx = idx + AV1394_PCR_ADDR_NOPCR - 1;
3597c478bd9Sstevel@tonic-gate 		} else {
3607c478bd9Sstevel@tonic-gate 			ASSERT(pip->pi_type == IEC61883_PLUG_IN);
3617c478bd9Sstevel@tonic-gate 			idx = AV1394_IPCR0_IDX;
3627c478bd9Sstevel@tonic-gate 			max_idx = idx + AV1394_PCR_ADDR_NIPCR - 1;
3637c478bd9Sstevel@tonic-gate 		}
3647c478bd9Sstevel@tonic-gate 
3657c478bd9Sstevel@tonic-gate 		/* find unused PCR */
3667c478bd9Sstevel@tonic-gate 		for (; idx <= max_idx; idx++) {
3677c478bd9Sstevel@tonic-gate 			if (cmp->cmp_pcr[idx] != NULL) {
3687c478bd9Sstevel@tonic-gate 				continue;
3697c478bd9Sstevel@tonic-gate 			}
3707c478bd9Sstevel@tonic-gate 			err = av1394_pcr_init(avp, idx, AV1394_PCR_INIT_VAL);
3717c478bd9Sstevel@tonic-gate 			if (err == DDI_SUCCESS) {
3727c478bd9Sstevel@tonic-gate 				break;
3737c478bd9Sstevel@tonic-gate 			}
3747c478bd9Sstevel@tonic-gate 		}
3757c478bd9Sstevel@tonic-gate 	} else {
3767c478bd9Sstevel@tonic-gate 		ph = av1394_pcr_make_ph(pip->pi_loc, pip->pi_type, pip->pi_num);
3777c478bd9Sstevel@tonic-gate 		idx = max_idx = av1394_pcr_ph2idx(ph);
3787c478bd9Sstevel@tonic-gate 
3797c478bd9Sstevel@tonic-gate 		/* create PCR if not already */
3807c478bd9Sstevel@tonic-gate 		if (cmp->cmp_pcr[idx] == NULL) {
3817c478bd9Sstevel@tonic-gate 			err = av1394_pcr_init(avp, idx, AV1394_PCR_INIT_VAL);
3827c478bd9Sstevel@tonic-gate 		}
3837c478bd9Sstevel@tonic-gate 	}
3847c478bd9Sstevel@tonic-gate 
3857c478bd9Sstevel@tonic-gate 	rw_exit(&cmp->cmp_pcr_rwlock);
3867c478bd9Sstevel@tonic-gate 
3877c478bd9Sstevel@tonic-gate 	if ((err != DDI_SUCCESS) || (idx > max_idx)) {
3887c478bd9Sstevel@tonic-gate 		return (EBUSY);
3897c478bd9Sstevel@tonic-gate 	}
3907c478bd9Sstevel@tonic-gate 	pip->pi_rnum = av1394_pcr_idx2num(idx);
3917c478bd9Sstevel@tonic-gate 	pip->pi_handle = av1394_pcr_make_ph(pip->pi_loc, pip->pi_type,
39247cd5876SAlan Perry 	    pip->pi_rnum);
3937c478bd9Sstevel@tonic-gate 
3947c478bd9Sstevel@tonic-gate 	return (0);
3957c478bd9Sstevel@tonic-gate }
3967c478bd9Sstevel@tonic-gate 
3977c478bd9Sstevel@tonic-gate /*
3987c478bd9Sstevel@tonic-gate  * IEC61883_PLUG_INIT for remote plugs
3997c478bd9Sstevel@tonic-gate  */
4007c478bd9Sstevel@tonic-gate static int
av1394_ioctl_plug_init_remote(av1394_inst_t * avp,iec61883_plug_init_t * pip)4017c478bd9Sstevel@tonic-gate av1394_ioctl_plug_init_remote(av1394_inst_t *avp, iec61883_plug_init_t *pip)
4027c478bd9Sstevel@tonic-gate {
4037c478bd9Sstevel@tonic-gate 	int		ph;
4047c478bd9Sstevel@tonic-gate 	uint32_t	val;
4057c478bd9Sstevel@tonic-gate 	int		ret;
4067c478bd9Sstevel@tonic-gate 
4077c478bd9Sstevel@tonic-gate 	if (pip->pi_num == IEC61883_PLUG_ANY) {
4087c478bd9Sstevel@tonic-gate 		return (EINVAL);
4097c478bd9Sstevel@tonic-gate 	}
4107c478bd9Sstevel@tonic-gate 
4117c478bd9Sstevel@tonic-gate 	ph = av1394_pcr_make_ph(pip->pi_loc, pip->pi_type, pip->pi_num);
4127c478bd9Sstevel@tonic-gate 
4137c478bd9Sstevel@tonic-gate 	/* check PCR existance by attempting to read it */
4147c478bd9Sstevel@tonic-gate 	if ((ret = av1394_pcr_remote_read(avp, ph, &val)) == 0) {
4157c478bd9Sstevel@tonic-gate 		pip->pi_handle = ph;
4167c478bd9Sstevel@tonic-gate 		pip->pi_rnum = pip->pi_num;
4177c478bd9Sstevel@tonic-gate 	}
4187c478bd9Sstevel@tonic-gate 
4197c478bd9Sstevel@tonic-gate 	return (ret);
4207c478bd9Sstevel@tonic-gate }
4217c478bd9Sstevel@tonic-gate 
4227c478bd9Sstevel@tonic-gate 
4237c478bd9Sstevel@tonic-gate /*
4247c478bd9Sstevel@tonic-gate  *
4257c478bd9Sstevel@tonic-gate  * --- plug routines
4267c478bd9Sstevel@tonic-gate  *
4277c478bd9Sstevel@tonic-gate  * initialize a PCR
4287c478bd9Sstevel@tonic-gate  */
4297c478bd9Sstevel@tonic-gate static int
av1394_pcr_init(av1394_inst_t * avp,int idx,uint32_t val)4307c478bd9Sstevel@tonic-gate av1394_pcr_init(av1394_inst_t *avp, int idx, uint32_t val)
4317c478bd9Sstevel@tonic-gate {
4327c478bd9Sstevel@tonic-gate 	av1394_cmp_t	*cmp = &avp->av_i.i_cmp;
4337c478bd9Sstevel@tonic-gate 	av1394_pcr_t	*pcr;
4347c478bd9Sstevel@tonic-gate 	uint64_t	addr;
4357c478bd9Sstevel@tonic-gate 	int		ret;
4367c478bd9Sstevel@tonic-gate 
4377c478bd9Sstevel@tonic-gate 	pcr = kmem_zalloc(sizeof (av1394_pcr_t), KM_SLEEP);
4387c478bd9Sstevel@tonic-gate 	pcr->pcr_val = val;
4397c478bd9Sstevel@tonic-gate 	cmp->cmp_pcr[idx] = pcr;
4407c478bd9Sstevel@tonic-gate 
4417c478bd9Sstevel@tonic-gate 	addr = av1394_pcr_idx2addr(idx);
4427c478bd9Sstevel@tonic-gate 	ret = av1394_pcr_alloc_addr(avp, addr, &pcr->pcr_addr_hdl);
4437c478bd9Sstevel@tonic-gate 	if (ret != DDI_SUCCESS) {
4447c478bd9Sstevel@tonic-gate 		kmem_free(pcr, sizeof (av1394_pcr_t));
4457c478bd9Sstevel@tonic-gate 		cmp->cmp_pcr[idx] = NULL;
4467c478bd9Sstevel@tonic-gate 	}
4477c478bd9Sstevel@tonic-gate 
4487c478bd9Sstevel@tonic-gate 	return (ret);
4497c478bd9Sstevel@tonic-gate }
4507c478bd9Sstevel@tonic-gate 
4517c478bd9Sstevel@tonic-gate /*
4527c478bd9Sstevel@tonic-gate  * finalize a PCR
4537c478bd9Sstevel@tonic-gate  */
4547c478bd9Sstevel@tonic-gate static void
av1394_pcr_fini(av1394_inst_t * avp,int idx)4557c478bd9Sstevel@tonic-gate av1394_pcr_fini(av1394_inst_t *avp, int idx)
4567c478bd9Sstevel@tonic-gate {
4577c478bd9Sstevel@tonic-gate 	av1394_cmp_t	*cmp = &avp->av_i.i_cmp;
4587c478bd9Sstevel@tonic-gate 
4597c478bd9Sstevel@tonic-gate 	av1394_pcr_free_addr(avp, &cmp->cmp_pcr[idx]->pcr_addr_hdl);
4607c478bd9Sstevel@tonic-gate 	kmem_free(cmp->cmp_pcr[idx], sizeof (av1394_pcr_t));
4617c478bd9Sstevel@tonic-gate 	cmp->cmp_pcr[idx] = NULL;
4627c478bd9Sstevel@tonic-gate }
4637c478bd9Sstevel@tonic-gate 
4647c478bd9Sstevel@tonic-gate /*
4657c478bd9Sstevel@tonic-gate  * allocate CSR address for a PCR
4667c478bd9Sstevel@tonic-gate  */
4677c478bd9Sstevel@tonic-gate static int
av1394_pcr_alloc_addr(av1394_inst_t * avp,uint64_t addr,t1394_addr_handle_t * hdlp)4687c478bd9Sstevel@tonic-gate av1394_pcr_alloc_addr(av1394_inst_t *avp, uint64_t addr,
4697c478bd9Sstevel@tonic-gate 		t1394_addr_handle_t *hdlp)
4707c478bd9Sstevel@tonic-gate {
4717c478bd9Sstevel@tonic-gate 	t1394_alloc_addr_t aa;
4727c478bd9Sstevel@tonic-gate 	int		ret;
4737c478bd9Sstevel@tonic-gate 	int		result;
4747c478bd9Sstevel@tonic-gate 
4757c478bd9Sstevel@tonic-gate 	bzero(&aa, sizeof (aa));
4767c478bd9Sstevel@tonic-gate 	aa.aa_address = addr;
4777c478bd9Sstevel@tonic-gate 	aa.aa_length = 4;
4787c478bd9Sstevel@tonic-gate 	aa.aa_type = T1394_ADDR_FIXED;
4797c478bd9Sstevel@tonic-gate 	aa.aa_enable = T1394_ADDR_RDENBL | T1394_ADDR_LKENBL;
4807c478bd9Sstevel@tonic-gate 	aa.aa_evts.recv_read_request = av1394_pcr_recv_read_request;
4817c478bd9Sstevel@tonic-gate 	aa.aa_evts.recv_lock_request = av1394_pcr_recv_lock_request;
4827c478bd9Sstevel@tonic-gate 	aa.aa_arg = avp;
4837c478bd9Sstevel@tonic-gate 
4847c478bd9Sstevel@tonic-gate 	ret = t1394_alloc_addr(avp->av_t1394_hdl, &aa, 0, &result);
485*2570281cSToomas Soome 	if (ret == DDI_SUCCESS) {
4867c478bd9Sstevel@tonic-gate 		*hdlp = aa.aa_hdl;
4877c478bd9Sstevel@tonic-gate 	}
4887c478bd9Sstevel@tonic-gate 
4897c478bd9Sstevel@tonic-gate 	return (ret);
4907c478bd9Sstevel@tonic-gate }
4917c478bd9Sstevel@tonic-gate 
4927c478bd9Sstevel@tonic-gate /*
4937c478bd9Sstevel@tonic-gate  * free CSR address occupied by a PCR
4947c478bd9Sstevel@tonic-gate  */
4957c478bd9Sstevel@tonic-gate static void
av1394_pcr_free_addr(av1394_inst_t * avp,t1394_addr_handle_t * hdlp)4967c478bd9Sstevel@tonic-gate av1394_pcr_free_addr(av1394_inst_t *avp, t1394_addr_handle_t *hdlp)
4977c478bd9Sstevel@tonic-gate {
498*2570281cSToomas Soome 	(void) t1394_free_addr(avp->av_t1394_hdl, hdlp, 0);
4997c478bd9Sstevel@tonic-gate }
5007c478bd9Sstevel@tonic-gate 
5017c478bd9Sstevel@tonic-gate /*
5027c478bd9Sstevel@tonic-gate  * make plug handle. range checking should be performed by caller
5037c478bd9Sstevel@tonic-gate  */
5047c478bd9Sstevel@tonic-gate static int
av1394_pcr_make_ph(int loc,int type,int num)5057c478bd9Sstevel@tonic-gate av1394_pcr_make_ph(int loc, int type, int num)
5067c478bd9Sstevel@tonic-gate {
5077c478bd9Sstevel@tonic-gate 	int	ph;
5087c478bd9Sstevel@tonic-gate 
5097c478bd9Sstevel@tonic-gate 	switch (type) {
5107c478bd9Sstevel@tonic-gate 	case IEC61883_PLUG_IN:
5117c478bd9Sstevel@tonic-gate 		ph = num + AV1394_IPCR0_IDX;
5127c478bd9Sstevel@tonic-gate 		break;
5137c478bd9Sstevel@tonic-gate 	case IEC61883_PLUG_OUT:
5147c478bd9Sstevel@tonic-gate 		ph = num + AV1394_OPCR0_IDX;
5157c478bd9Sstevel@tonic-gate 		break;
5167c478bd9Sstevel@tonic-gate 	case IEC61883_PLUG_MASTER_IN:
5177c478bd9Sstevel@tonic-gate 		ph = AV1394_IMPR_IDX;
5187c478bd9Sstevel@tonic-gate 		break;
5197c478bd9Sstevel@tonic-gate 	case IEC61883_PLUG_MASTER_OUT:
5207c478bd9Sstevel@tonic-gate 		ph = AV1394_OMPR_IDX;
5217c478bd9Sstevel@tonic-gate 		break;
5227c478bd9Sstevel@tonic-gate 	default:
5237c478bd9Sstevel@tonic-gate 		ASSERT(0);
5247c478bd9Sstevel@tonic-gate 	}
5257c478bd9Sstevel@tonic-gate 
5267c478bd9Sstevel@tonic-gate 	if (loc == IEC61883_LOC_REMOTE) {
5277c478bd9Sstevel@tonic-gate 		ph |= AV1394_PCR_REMOTE;
5287c478bd9Sstevel@tonic-gate 	}
5297c478bd9Sstevel@tonic-gate 
5307c478bd9Sstevel@tonic-gate 	return (ph);
5317c478bd9Sstevel@tonic-gate }
5327c478bd9Sstevel@tonic-gate 
5337c478bd9Sstevel@tonic-gate /*
5347c478bd9Sstevel@tonic-gate  * convert plug handle to PCR index
5357c478bd9Sstevel@tonic-gate  */
5367c478bd9Sstevel@tonic-gate static int
av1394_pcr_ph2idx(int ph)5377c478bd9Sstevel@tonic-gate av1394_pcr_ph2idx(int ph)
5387c478bd9Sstevel@tonic-gate {
5397c478bd9Sstevel@tonic-gate 	return (ph & ~AV1394_PCR_REMOTE);
5407c478bd9Sstevel@tonic-gate }
5417c478bd9Sstevel@tonic-gate 
5427c478bd9Sstevel@tonic-gate /*
5437c478bd9Sstevel@tonic-gate  * convert plug handle to PCR pointer
5447c478bd9Sstevel@tonic-gate  */
5457c478bd9Sstevel@tonic-gate static av1394_pcr_t *
av1394_pcr_ph2pcr(av1394_cmp_t * cmp,int ph)5467c478bd9Sstevel@tonic-gate av1394_pcr_ph2pcr(av1394_cmp_t *cmp, int ph)
5477c478bd9Sstevel@tonic-gate {
5487c478bd9Sstevel@tonic-gate 	int	idx = av1394_pcr_ph2idx(ph);
5497c478bd9Sstevel@tonic-gate 
5507c478bd9Sstevel@tonic-gate 	if ((idx >= 0) && (idx < NELEM(cmp->cmp_pcr))) {
5517c478bd9Sstevel@tonic-gate 		return (cmp->cmp_pcr[idx]);
5527c478bd9Sstevel@tonic-gate 	} else {
5537c478bd9Sstevel@tonic-gate 		return (NULL);
5547c478bd9Sstevel@tonic-gate 	}
5557c478bd9Sstevel@tonic-gate }
5567c478bd9Sstevel@tonic-gate 
5577c478bd9Sstevel@tonic-gate /*
5587c478bd9Sstevel@tonic-gate  * convert PCR index to CSR address
5597c478bd9Sstevel@tonic-gate  */
5607c478bd9Sstevel@tonic-gate static uint64_t
av1394_pcr_idx2addr(int idx)5617c478bd9Sstevel@tonic-gate av1394_pcr_idx2addr(int idx)
5627c478bd9Sstevel@tonic-gate {
5637c478bd9Sstevel@tonic-gate 	return (AV1394_PCR_ADDR_START + idx * 4);
5647c478bd9Sstevel@tonic-gate }
5657c478bd9Sstevel@tonic-gate 
5667c478bd9Sstevel@tonic-gate /*
5677c478bd9Sstevel@tonic-gate  * convert PCR index to number
5687c478bd9Sstevel@tonic-gate  */
5697c478bd9Sstevel@tonic-gate static int
av1394_pcr_idx2num(int idx)5707c478bd9Sstevel@tonic-gate av1394_pcr_idx2num(int idx)
5717c478bd9Sstevel@tonic-gate {
5727c478bd9Sstevel@tonic-gate 	ASSERT(!av1394_pcr_idx_is_mpr(idx));
5737c478bd9Sstevel@tonic-gate 
5747c478bd9Sstevel@tonic-gate 	return ((idx - 1) % 32);
5757c478bd9Sstevel@tonic-gate }
5767c478bd9Sstevel@tonic-gate 
5777c478bd9Sstevel@tonic-gate /*
5787c478bd9Sstevel@tonic-gate  * returns B_TRUE if a master plug
5797c478bd9Sstevel@tonic-gate  */
5807c478bd9Sstevel@tonic-gate static boolean_t
av1394_pcr_idx_is_mpr(int idx)5817c478bd9Sstevel@tonic-gate av1394_pcr_idx_is_mpr(int idx)
5827c478bd9Sstevel@tonic-gate {
5837c478bd9Sstevel@tonic-gate 	return (idx % 32 == 0);
5847c478bd9Sstevel@tonic-gate }
5857c478bd9Sstevel@tonic-gate 
5867c478bd9Sstevel@tonic-gate static boolean_t
av1394_pcr_ph_is_mpr(int ph)5877c478bd9Sstevel@tonic-gate av1394_pcr_ph_is_mpr(int ph)
5887c478bd9Sstevel@tonic-gate {
5897c478bd9Sstevel@tonic-gate 	return (av1394_pcr_ph2idx(ph) % 32 == 0);
5907c478bd9Sstevel@tonic-gate }
5917c478bd9Sstevel@tonic-gate 
5927c478bd9Sstevel@tonic-gate /*
5937c478bd9Sstevel@tonic-gate  * returns B_TRUE if a remote plug
5947c478bd9Sstevel@tonic-gate  */
5957c478bd9Sstevel@tonic-gate static boolean_t
av1394_pcr_ph_is_remote(int ph)5967c478bd9Sstevel@tonic-gate av1394_pcr_ph_is_remote(int ph)
5977c478bd9Sstevel@tonic-gate {
5987c478bd9Sstevel@tonic-gate 	return ((ph & AV1394_PCR_REMOTE) != 0);
5997c478bd9Sstevel@tonic-gate }
6007c478bd9Sstevel@tonic-gate 
6017c478bd9Sstevel@tonic-gate 
6027c478bd9Sstevel@tonic-gate /*
6037c478bd9Sstevel@tonic-gate  *
6047c478bd9Sstevel@tonic-gate  * --- callbacks
6057c478bd9Sstevel@tonic-gate  *
6067c478bd9Sstevel@tonic-gate  */
6077c478bd9Sstevel@tonic-gate static void
av1394_pcr_recv_read_request(cmd1394_cmd_t * req)6087c478bd9Sstevel@tonic-gate av1394_pcr_recv_read_request(cmd1394_cmd_t *req)
6097c478bd9Sstevel@tonic-gate {
6107c478bd9Sstevel@tonic-gate 	av1394_inst_t	*avp = req->cmd_callback_arg;
6117c478bd9Sstevel@tonic-gate 	av1394_cmp_t	*cmp = &avp->av_i.i_cmp;
6127c478bd9Sstevel@tonic-gate 	int		idx;	/* PCR index */
6137c478bd9Sstevel@tonic-gate 	av1394_pcr_t	*pcr;
6147c478bd9Sstevel@tonic-gate 
6157c478bd9Sstevel@tonic-gate 	idx = (req->cmd_addr - AV1394_PCR_ADDR_START) / 4;
6167c478bd9Sstevel@tonic-gate 
6177c478bd9Sstevel@tonic-gate 	if (req->cmd_type != CMD1394_ASYNCH_RD_QUAD) {
6187c478bd9Sstevel@tonic-gate 		req->cmd_result = IEEE1394_RESP_TYPE_ERROR;
61947cd5876SAlan Perry 	} else if ((idx >= NELEM(cmp->cmp_pcr)) ||
6207c478bd9Sstevel@tonic-gate 	    ((pcr = cmp->cmp_pcr[idx]) == NULL)) {
6217c478bd9Sstevel@tonic-gate 		req->cmd_result = IEEE1394_RESP_ADDRESS_ERROR;
6227c478bd9Sstevel@tonic-gate 	} else {
6237c478bd9Sstevel@tonic-gate 		/* read */
6247c478bd9Sstevel@tonic-gate 		rw_enter(&cmp->cmp_pcr_rwlock, RW_READER);
6257c478bd9Sstevel@tonic-gate 		req->cmd_u.q.quadlet_data = pcr->pcr_val;
6267c478bd9Sstevel@tonic-gate 		rw_exit(&cmp->cmp_pcr_rwlock);
6277c478bd9Sstevel@tonic-gate 
6287c478bd9Sstevel@tonic-gate 		req->cmd_result = IEEE1394_RESP_COMPLETE;
6297c478bd9Sstevel@tonic-gate 	}
6307c478bd9Sstevel@tonic-gate 
631*2570281cSToomas Soome 	(void) t1394_recv_request_done(avp->av_t1394_hdl, req, 0);
6327c478bd9Sstevel@tonic-gate }
6337c478bd9Sstevel@tonic-gate 
6347c478bd9Sstevel@tonic-gate static void
av1394_pcr_recv_lock_request(cmd1394_cmd_t * req)6357c478bd9Sstevel@tonic-gate av1394_pcr_recv_lock_request(cmd1394_cmd_t *req)
6367c478bd9Sstevel@tonic-gate {
6377c478bd9Sstevel@tonic-gate 	av1394_inst_t	*avp = req->cmd_callback_arg;
6387c478bd9Sstevel@tonic-gate 	av1394_cmp_t	*cmp = &avp->av_i.i_cmp;
6397c478bd9Sstevel@tonic-gate 	int		idx;	/* PCR index */
6407c478bd9Sstevel@tonic-gate 	av1394_pcr_t	*pcr;
6417c478bd9Sstevel@tonic-gate 
6427c478bd9Sstevel@tonic-gate 	idx = (req->cmd_addr - AV1394_PCR_ADDR_START) / 4;
6437c478bd9Sstevel@tonic-gate 
6447c478bd9Sstevel@tonic-gate 	if ((req->cmd_type != CMD1394_ASYNCH_LOCK_32) ||
6457c478bd9Sstevel@tonic-gate 	    (req->cmd_u.l32.lock_type != CMD1394_LOCK_COMPARE_SWAP)) {
6467c478bd9Sstevel@tonic-gate 		req->cmd_result = IEEE1394_RESP_TYPE_ERROR;
64747cd5876SAlan Perry 	} else if ((idx >= NELEM(cmp->cmp_pcr)) ||
6487c478bd9Sstevel@tonic-gate 	    ((pcr = cmp->cmp_pcr[idx]) == NULL)) {
6497c478bd9Sstevel@tonic-gate 		req->cmd_result = IEEE1394_RESP_ADDRESS_ERROR;
6507c478bd9Sstevel@tonic-gate 	} else {
6517c478bd9Sstevel@tonic-gate 		/* compare_swap */
6527c478bd9Sstevel@tonic-gate 		rw_enter(&cmp->cmp_pcr_rwlock, RW_WRITER);
6537c478bd9Sstevel@tonic-gate 		if (pcr->pcr_val == req->cmd_u.l32.arg_value) {
6547c478bd9Sstevel@tonic-gate 			pcr->pcr_val = req->cmd_u.l32.data_value;
6557c478bd9Sstevel@tonic-gate 		}
6567c478bd9Sstevel@tonic-gate 		req->cmd_u.l32.old_value = pcr->pcr_val;
6577c478bd9Sstevel@tonic-gate 		rw_exit(&cmp->cmp_pcr_rwlock);
6587c478bd9Sstevel@tonic-gate 
6597c478bd9Sstevel@tonic-gate 		req->cmd_result = IEEE1394_RESP_COMPLETE;
6607c478bd9Sstevel@tonic-gate 	}
6617c478bd9Sstevel@tonic-gate 
662*2570281cSToomas Soome 	(void) t1394_recv_request_done(avp->av_t1394_hdl, req, 0);
6637c478bd9Sstevel@tonic-gate }
6647c478bd9Sstevel@tonic-gate 
6657c478bd9Sstevel@tonic-gate 
6667c478bd9Sstevel@tonic-gate /*
6677c478bd9Sstevel@tonic-gate  *
6687c478bd9Sstevel@tonic-gate  * --- remote PCR routines
6697c478bd9Sstevel@tonic-gate  *
6707c478bd9Sstevel@tonic-gate  * read specified PCR on the remote node
6717c478bd9Sstevel@tonic-gate  */
6727c478bd9Sstevel@tonic-gate static int
av1394_pcr_remote_read(av1394_inst_t * avp,int ph,uint32_t * valp)6737c478bd9Sstevel@tonic-gate av1394_pcr_remote_read(av1394_inst_t *avp, int ph, uint32_t *valp)
6747c478bd9Sstevel@tonic-gate {
6757c478bd9Sstevel@tonic-gate 	cmd1394_cmd_t	*cmd;
6767c478bd9Sstevel@tonic-gate 	int		ret = 0;
6777c478bd9Sstevel@tonic-gate 	int		err;
6787c478bd9Sstevel@tonic-gate 
6797c478bd9Sstevel@tonic-gate 	ret = t1394_alloc_cmd(avp->av_t1394_hdl, 0, &cmd);
6807c478bd9Sstevel@tonic-gate 	if (ret != DDI_SUCCESS) {
6817c478bd9Sstevel@tonic-gate 		return (ENOMEM);
6827c478bd9Sstevel@tonic-gate 	}
6837c478bd9Sstevel@tonic-gate 
6847c478bd9Sstevel@tonic-gate 	cmd->cmd_addr = av1394_pcr_idx2addr(av1394_pcr_ph2idx(ph));
6857c478bd9Sstevel@tonic-gate 	cmd->cmd_type = CMD1394_ASYNCH_RD_QUAD;
6867c478bd9Sstevel@tonic-gate 	cmd->cmd_options = CMD1394_BLOCKING;
6877c478bd9Sstevel@tonic-gate 
6887c478bd9Sstevel@tonic-gate 	if (((err = t1394_read(avp->av_t1394_hdl, cmd)) == DDI_SUCCESS) &&
6897c478bd9Sstevel@tonic-gate 	    (cmd->cmd_result == CMD1394_CMDSUCCESS)) {
6907c478bd9Sstevel@tonic-gate 		*valp = cmd->cmd_u.q.quadlet_data;
6917c478bd9Sstevel@tonic-gate 	} else {
6927c478bd9Sstevel@tonic-gate 		ret = EIO;
6937c478bd9Sstevel@tonic-gate 	}
6947c478bd9Sstevel@tonic-gate 
6957c478bd9Sstevel@tonic-gate 	err = t1394_free_cmd(avp->av_t1394_hdl, 0, &cmd);
6967c478bd9Sstevel@tonic-gate 	ASSERT(err == DDI_SUCCESS);
6977c478bd9Sstevel@tonic-gate 
6987c478bd9Sstevel@tonic-gate 	return (ret);
6997c478bd9Sstevel@tonic-gate }
7007c478bd9Sstevel@tonic-gate 
7017c478bd9Sstevel@tonic-gate /*
7027c478bd9Sstevel@tonic-gate  * compare_swap specified PCR on the remote node
7037c478bd9Sstevel@tonic-gate  */
7047c478bd9Sstevel@tonic-gate static int
av1394_pcr_remote_cas(av1394_inst_t * avp,int ph,uint32_t * old_valuep,uint32_t data_value,uint32_t arg_value)7057c478bd9Sstevel@tonic-gate av1394_pcr_remote_cas(av1394_inst_t *avp, int ph, uint32_t *old_valuep,
7067c478bd9Sstevel@tonic-gate 		uint32_t data_value, uint32_t arg_value)
7077c478bd9Sstevel@tonic-gate {
7087c478bd9Sstevel@tonic-gate 	cmd1394_cmd_t	*cmd;
7097c478bd9Sstevel@tonic-gate 	int		ret = 0;
7107c478bd9Sstevel@tonic-gate 	int		err;
7117c478bd9Sstevel@tonic-gate 
7127c478bd9Sstevel@tonic-gate 	ret = t1394_alloc_cmd(avp->av_t1394_hdl, 0, &cmd);
7137c478bd9Sstevel@tonic-gate 	if (ret != DDI_SUCCESS) {
7147c478bd9Sstevel@tonic-gate 		return (ENOMEM);
7157c478bd9Sstevel@tonic-gate 	}
7167c478bd9Sstevel@tonic-gate 
7177c478bd9Sstevel@tonic-gate 	cmd->cmd_addr = av1394_pcr_idx2addr(av1394_pcr_ph2idx(ph));
7187c478bd9Sstevel@tonic-gate 	cmd->cmd_type = CMD1394_ASYNCH_LOCK_32;
7197c478bd9Sstevel@tonic-gate 	cmd->cmd_u.l32.lock_type = CMD1394_LOCK_COMPARE_SWAP;
7207c478bd9Sstevel@tonic-gate 	cmd->cmd_u.l32.data_value = data_value;
7217c478bd9Sstevel@tonic-gate 	cmd->cmd_u.l32.arg_value = arg_value;
7227c478bd9Sstevel@tonic-gate 	cmd->cmd_u.l32.num_retries = 0;
7237c478bd9Sstevel@tonic-gate 	cmd->cmd_options = CMD1394_BLOCKING;
7247c478bd9Sstevel@tonic-gate 
7257c478bd9Sstevel@tonic-gate 	if (((err = t1394_lock(avp->av_t1394_hdl, cmd)) == DDI_SUCCESS) &&
7267c478bd9Sstevel@tonic-gate 	    (cmd->cmd_result == CMD1394_CMDSUCCESS)) {
7277c478bd9Sstevel@tonic-gate 		*old_valuep = cmd->cmd_u.l32.old_value;
7287c478bd9Sstevel@tonic-gate 	} else {
7297c478bd9Sstevel@tonic-gate 		ret = EIO;
7307c478bd9Sstevel@tonic-gate 	}
7317c478bd9Sstevel@tonic-gate 
7327c478bd9Sstevel@tonic-gate 	err = t1394_free_cmd(avp->av_t1394_hdl, 0, &cmd);
7337c478bd9Sstevel@tonic-gate 	ASSERT(err == DDI_SUCCESS);
7347c478bd9Sstevel@tonic-gate 
7357c478bd9Sstevel@tonic-gate 	return (ret);
7367c478bd9Sstevel@tonic-gate }
737