xref: /onnv-gate/usr/src/uts/common/io/lvm/trans/trans_ioctl.c (revision 9017:47960a78ed2a)
10Sstevel@tonic-gate /*
20Sstevel@tonic-gate  * CDDL HEADER START
30Sstevel@tonic-gate  *
40Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
55331Samw  * Common Development and Distribution License (the "License").
65331Samw  * You may not use this file except in compliance with the License.
70Sstevel@tonic-gate  *
80Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
90Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
100Sstevel@tonic-gate  * See the License for the specific language governing permissions
110Sstevel@tonic-gate  * and limitations under the License.
120Sstevel@tonic-gate  *
130Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
140Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
150Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
160Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
170Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
180Sstevel@tonic-gate  *
190Sstevel@tonic-gate  * CDDL HEADER END
200Sstevel@tonic-gate  */
217563SPrasad.Singamsetty@Sun.COM 
220Sstevel@tonic-gate /*
23*9017SJohn.Wren.Kennedy@Sun.COM  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
240Sstevel@tonic-gate  * Use is subject to license terms.
250Sstevel@tonic-gate  */
260Sstevel@tonic-gate 
270Sstevel@tonic-gate #include <sys/param.h>
280Sstevel@tonic-gate #include <sys/systm.h>
290Sstevel@tonic-gate #include <sys/conf.h>
300Sstevel@tonic-gate #include <sys/file.h>
310Sstevel@tonic-gate #include <sys/user.h>
320Sstevel@tonic-gate #include <sys/uio.h>
330Sstevel@tonic-gate #include <sys/t_lock.h>
340Sstevel@tonic-gate #include <sys/dkio.h>
350Sstevel@tonic-gate #include <sys/vtoc.h>
360Sstevel@tonic-gate #include <sys/kmem.h>
370Sstevel@tonic-gate #include <vm/page.h>
380Sstevel@tonic-gate #include <sys/cmn_err.h>
390Sstevel@tonic-gate #include <sys/sysmacros.h>
400Sstevel@tonic-gate #include <sys/types.h>
410Sstevel@tonic-gate #include <sys/mkdev.h>
420Sstevel@tonic-gate #include <sys/stat.h>
430Sstevel@tonic-gate #include <sys/open.h>
440Sstevel@tonic-gate #include <sys/lvm/md_trans.h>
450Sstevel@tonic-gate #include <sys/modctl.h>
460Sstevel@tonic-gate #include <sys/ddi.h>
470Sstevel@tonic-gate #include <sys/sunddi.h>
480Sstevel@tonic-gate #include <sys/debug.h>
490Sstevel@tonic-gate #include <sys/filio.h>
500Sstevel@tonic-gate #include <sys/lvm/md_notify.h>
510Sstevel@tonic-gate #include <sys/callb.h>
520Sstevel@tonic-gate #include <sys/disp.h>
530Sstevel@tonic-gate 
540Sstevel@tonic-gate #include <sys/sysevent/eventdefs.h>
550Sstevel@tonic-gate #include <sys/sysevent/svm.h>
560Sstevel@tonic-gate 
570Sstevel@tonic-gate extern int		md_status;
580Sstevel@tonic-gate extern unit_t		md_nunits;
590Sstevel@tonic-gate extern set_t		md_nsets;
600Sstevel@tonic-gate extern md_set_t		md_set[];
610Sstevel@tonic-gate extern md_ops_t		trans_md_ops;
620Sstevel@tonic-gate extern md_krwlock_t	md_unit_array_rw;
630Sstevel@tonic-gate extern uint_t		mt_debug;
640Sstevel@tonic-gate 
650Sstevel@tonic-gate extern major_t	md_major;
660Sstevel@tonic-gate 
670Sstevel@tonic-gate static mt_unit_t *
trans_getun(minor_t mnum,md_error_t * mde,int flags,IOLOCK * lock)680Sstevel@tonic-gate trans_getun(minor_t mnum, md_error_t *mde, int flags, IOLOCK *lock)
690Sstevel@tonic-gate {
700Sstevel@tonic-gate 	mt_unit_t	*un;
710Sstevel@tonic-gate 	mdi_unit_t	*ui;
720Sstevel@tonic-gate 	set_t		setno = MD_MIN2SET(mnum);
730Sstevel@tonic-gate 
740Sstevel@tonic-gate 	if ((setno >= md_nsets) || (MD_MIN2UNIT(mnum) >= md_nunits)) {
750Sstevel@tonic-gate 		(void) mdmderror(mde, MDE_INVAL_UNIT, mnum);
760Sstevel@tonic-gate 		return (NULL);
770Sstevel@tonic-gate 	}
780Sstevel@tonic-gate 
790Sstevel@tonic-gate 	if (! (flags & STALE_OK)) {
800Sstevel@tonic-gate 		if (md_get_setstatus(setno) & MD_SET_STALE) {
810Sstevel@tonic-gate 			(void) mdmddberror(mde, MDE_DB_STALE, mnum, setno);
820Sstevel@tonic-gate 			return (NULL);
830Sstevel@tonic-gate 		}
840Sstevel@tonic-gate 	}
850Sstevel@tonic-gate 
860Sstevel@tonic-gate 	ui = MDI_UNIT(mnum);
870Sstevel@tonic-gate 	if (flags & NO_OLD) {
880Sstevel@tonic-gate 		if (ui != NULL) {
890Sstevel@tonic-gate 			(void) mdmderror(mde, MDE_UNIT_ALREADY_SETUP, mnum);
900Sstevel@tonic-gate 			return (NULL);
910Sstevel@tonic-gate 		}
920Sstevel@tonic-gate 		return ((mt_unit_t *)1);
930Sstevel@tonic-gate 	}
940Sstevel@tonic-gate 
950Sstevel@tonic-gate 	if (ui == NULL) {
960Sstevel@tonic-gate 		(void) mdmderror(mde, MDE_UNIT_NOT_SETUP, mnum);
970Sstevel@tonic-gate 		return (NULL);
980Sstevel@tonic-gate 	}
990Sstevel@tonic-gate 
1000Sstevel@tonic-gate 	if (flags & ARRAY_WRITER)
1010Sstevel@tonic-gate 		md_array_writer(lock);
1020Sstevel@tonic-gate 	else if (flags & ARRAY_READER)
1030Sstevel@tonic-gate 		md_array_reader(lock);
1040Sstevel@tonic-gate 
1050Sstevel@tonic-gate 	if (!(flags & NO_LOCK)) {
1060Sstevel@tonic-gate 		if (flags & WR_LOCK)
1070Sstevel@tonic-gate 			(void) md_ioctl_writerlock(lock, ui);
1080Sstevel@tonic-gate 		else /* RD_LOCK */
1090Sstevel@tonic-gate 			(void) md_ioctl_readerlock(lock, ui);
1100Sstevel@tonic-gate 	}
1110Sstevel@tonic-gate 	un = (mt_unit_t *)MD_UNIT(mnum);
1120Sstevel@tonic-gate 
1130Sstevel@tonic-gate 	if (un->c.un_type != MD_METATRANS) {
1140Sstevel@tonic-gate 		(void) mdmderror(mde, MDE_NOT_MT, mnum);
1150Sstevel@tonic-gate 		return (NULL);
1160Sstevel@tonic-gate 	}
1170Sstevel@tonic-gate 
1180Sstevel@tonic-gate 	return (un);
1190Sstevel@tonic-gate }
1200Sstevel@tonic-gate 
1210Sstevel@tonic-gate #ifdef	DEBUG
1220Sstevel@tonic-gate /*
1230Sstevel@tonic-gate  * DEBUG ROUTINES
1240Sstevel@tonic-gate  * 	THESE ROUTINES ARE ONLY USED WHEN ASSERTS ARE ENABLED
1250Sstevel@tonic-gate  */
1260Sstevel@tonic-gate 
1270Sstevel@tonic-gate extern int		(*mdv_strategy_tstpnt)(buf_t *, int, void*);
1280Sstevel@tonic-gate 
1290Sstevel@tonic-gate /*
1300Sstevel@tonic-gate  * return the global stats struct
1310Sstevel@tonic-gate  */
1320Sstevel@tonic-gate static int
trans_get_transstats(void * d,int mode)1330Sstevel@tonic-gate trans_get_transstats(void *d, int mode)
1340Sstevel@tonic-gate {
1350Sstevel@tonic-gate 	md_i_get_t *migp = d;
1360Sstevel@tonic-gate 
1370Sstevel@tonic-gate 	mdclrerror(&migp->mde);
1380Sstevel@tonic-gate 
1390Sstevel@tonic-gate 	if (migp->size == 0) {
1400Sstevel@tonic-gate 		migp->size = sizeof (struct transstats);
1410Sstevel@tonic-gate 		return (0);
1420Sstevel@tonic-gate 	}
1430Sstevel@tonic-gate 
1440Sstevel@tonic-gate 	if (migp->size < sizeof (struct transstats))
1450Sstevel@tonic-gate 		return (EFAULT);
1460Sstevel@tonic-gate 
1470Sstevel@tonic-gate 	if (ddi_copyout(&transstats, (caddr_t)(uintptr_t)migp->mdp,
1480Sstevel@tonic-gate 	    sizeof (struct transstats), mode))
1490Sstevel@tonic-gate 		return (EFAULT);
1500Sstevel@tonic-gate 	return (0);
1510Sstevel@tonic-gate }
1520Sstevel@tonic-gate 
1530Sstevel@tonic-gate /*
1540Sstevel@tonic-gate  * test ioctls
1550Sstevel@tonic-gate  */
1560Sstevel@tonic-gate /*
1570Sstevel@tonic-gate  * TEST TRYGETBLK
1580Sstevel@tonic-gate  */
1590Sstevel@tonic-gate /*ARGSUSED1*/
1600Sstevel@tonic-gate static int
trans_test_trygetblk(void * d,int mode,IOLOCK * lock)1610Sstevel@tonic-gate trans_test_trygetblk(void *d, int mode, IOLOCK *lock)
1620Sstevel@tonic-gate {
1630Sstevel@tonic-gate 	mt_unit_t	*un;
1640Sstevel@tonic-gate 	int		test;
1650Sstevel@tonic-gate 	dev_t		dev;
1660Sstevel@tonic-gate 	struct buf	*bp;
1670Sstevel@tonic-gate 	struct buf	*trygetblk();
1680Sstevel@tonic-gate 
1690Sstevel@tonic-gate 	md_i_get_t *migp = d;
1700Sstevel@tonic-gate 
1710Sstevel@tonic-gate 	mdclrerror(&migp->mde);
1720Sstevel@tonic-gate 	migp->size = 0;
1730Sstevel@tonic-gate 
1740Sstevel@tonic-gate 	un = trans_getun(migp->id, &migp->mde,
1757563SPrasad.Singamsetty@Sun.COM 	    RD_LOCK, lock);
1760Sstevel@tonic-gate 	if (un == NULL)
1770Sstevel@tonic-gate 		return (EINVAL);
1780Sstevel@tonic-gate 
1790Sstevel@tonic-gate 	dev = un->un_m_dev;
1800Sstevel@tonic-gate 
1810Sstevel@tonic-gate 	/*
1820Sstevel@tonic-gate 	 * test 1 -- don't find nonexistant buf
1830Sstevel@tonic-gate 	 */
1840Sstevel@tonic-gate 	test = 1;
1850Sstevel@tonic-gate 	if (bp = trygetblk(dev, 0))
1860Sstevel@tonic-gate 		goto errout;
1870Sstevel@tonic-gate 
1880Sstevel@tonic-gate 	/*
1890Sstevel@tonic-gate 	 * test 2 - don't find stale buf
1900Sstevel@tonic-gate 	 */
1910Sstevel@tonic-gate 	test = 2;
1920Sstevel@tonic-gate 	if ((bp = getblk(dev, 0, DEV_BSIZE)) == NULL)
1930Sstevel@tonic-gate 		goto errout;
1940Sstevel@tonic-gate 	bp->b_flags |= (B_STALE|B_DONE);
1950Sstevel@tonic-gate 	brelse(bp);
1960Sstevel@tonic-gate 	if (bp = trygetblk(dev, 0))
1970Sstevel@tonic-gate 		goto errout;
1980Sstevel@tonic-gate 
1990Sstevel@tonic-gate 	/*
2000Sstevel@tonic-gate 	 * test 3 -- don't find busy buf
2010Sstevel@tonic-gate 	 */
2020Sstevel@tonic-gate 	test = 3;
2030Sstevel@tonic-gate 	if ((bp = getblk(dev, 0, DEV_BSIZE)) == NULL)
2040Sstevel@tonic-gate 		goto errout;
2050Sstevel@tonic-gate 	if (trygetblk(dev, 0))
2060Sstevel@tonic-gate 		goto errout;
2070Sstevel@tonic-gate 	bp->b_flags |= B_STALE;
2080Sstevel@tonic-gate 	brelse(bp);
2090Sstevel@tonic-gate 
2100Sstevel@tonic-gate 	/*
2110Sstevel@tonic-gate 	 * test 4 -- don't find not-done buf
2120Sstevel@tonic-gate 	 */
2130Sstevel@tonic-gate 	test = 4;
2140Sstevel@tonic-gate 	if ((bp = getblk(dev, 0, DEV_BSIZE)) == NULL)
2150Sstevel@tonic-gate 		goto errout;
2160Sstevel@tonic-gate 	brelse(bp);
2170Sstevel@tonic-gate 	if (bp = trygetblk(dev, 0))
2180Sstevel@tonic-gate 		goto errout;
2190Sstevel@tonic-gate 
2200Sstevel@tonic-gate 	/*
2210Sstevel@tonic-gate 	 * test 5 -- find an idle buf
2220Sstevel@tonic-gate 	 */
2230Sstevel@tonic-gate 	test = 5;
2240Sstevel@tonic-gate 	if ((bp = bread(dev, 0, DEV_BSIZE)) == NULL)
2250Sstevel@tonic-gate 		goto errout;
2260Sstevel@tonic-gate 	brelse(bp);
2270Sstevel@tonic-gate 	if ((bp = trygetblk(dev, 0)) == NULL)
2280Sstevel@tonic-gate 		goto errout;
2290Sstevel@tonic-gate 	bp->b_flags |= B_STALE;
2300Sstevel@tonic-gate 	brelse(bp);
2310Sstevel@tonic-gate 	bp = 0;
2320Sstevel@tonic-gate 
2330Sstevel@tonic-gate 	test = 0;	/* no test failed */
2340Sstevel@tonic-gate errout:
2350Sstevel@tonic-gate 	if (bp) {
2360Sstevel@tonic-gate 		bp->b_flags |= B_STALE;
2370Sstevel@tonic-gate 		brelse(bp);
2380Sstevel@tonic-gate 	}
2390Sstevel@tonic-gate 	migp->size = test;
2400Sstevel@tonic-gate 	if (test)
2410Sstevel@tonic-gate 		return (EINVAL);
2420Sstevel@tonic-gate 	return (0);
2430Sstevel@tonic-gate }
2440Sstevel@tonic-gate /*
2450Sstevel@tonic-gate  * TEST TRYGETPAGE
2460Sstevel@tonic-gate  */
2470Sstevel@tonic-gate static page_t *
trans_trypage(struct vnode * vp,uint_t off)2480Sstevel@tonic-gate trans_trypage(struct vnode *vp, uint_t off)
2490Sstevel@tonic-gate {
2500Sstevel@tonic-gate 	page_t		*pp;
2510Sstevel@tonic-gate 
2520Sstevel@tonic-gate 	/*
2530Sstevel@tonic-gate 	 * get a locked page
2540Sstevel@tonic-gate 	 */
2550Sstevel@tonic-gate 	if ((pp = page_lookup_nowait(vp, off, SE_EXCL)) == NULL)
2560Sstevel@tonic-gate 		return (NULL);
2570Sstevel@tonic-gate 	/*
2580Sstevel@tonic-gate 	 * get the iolock
2590Sstevel@tonic-gate 	 */
2600Sstevel@tonic-gate 	if (!page_io_trylock(pp)) {
2610Sstevel@tonic-gate 		page_unlock(pp);
2620Sstevel@tonic-gate 		return (NULL);
2630Sstevel@tonic-gate 	}
2640Sstevel@tonic-gate 	return (pp);
2650Sstevel@tonic-gate }
2660Sstevel@tonic-gate 
2670Sstevel@tonic-gate /*ARGSUSED1*/
2680Sstevel@tonic-gate static int
trans_test_trypage(void * d,int mode,IOLOCK * lock)2690Sstevel@tonic-gate trans_test_trypage(void *d, int mode, IOLOCK *lock)
2700Sstevel@tonic-gate {
2710Sstevel@tonic-gate 	mt_unit_t		*un;
2720Sstevel@tonic-gate 	int			test;
2730Sstevel@tonic-gate 	dev_t			dev;
2740Sstevel@tonic-gate 	struct page		*pp;
2750Sstevel@tonic-gate 	struct vnode		*devvp;
2760Sstevel@tonic-gate 	struct vnode		*cvp;
2770Sstevel@tonic-gate 	extern struct vnode	*common_specvp(struct vnode *);
2780Sstevel@tonic-gate 	extern void		pvn_io_done(struct page *);
2790Sstevel@tonic-gate 
2800Sstevel@tonic-gate 	md_i_get_t *migp = d;
2810Sstevel@tonic-gate 
2820Sstevel@tonic-gate 	mdclrerror(&migp->mde);
2830Sstevel@tonic-gate 	migp->size = 0;
2840Sstevel@tonic-gate 
2850Sstevel@tonic-gate 	un = trans_getun(migp->id, &migp->mde,
2867563SPrasad.Singamsetty@Sun.COM 	    RD_LOCK, lock);
2870Sstevel@tonic-gate 	if (un == NULL)
2880Sstevel@tonic-gate 		return (EINVAL);
2890Sstevel@tonic-gate 
2900Sstevel@tonic-gate 	dev = un->un_m_dev;
2910Sstevel@tonic-gate 	devvp = makespecvp(dev, VBLK);
2920Sstevel@tonic-gate 	cvp = common_specvp(devvp);
2930Sstevel@tonic-gate 
2940Sstevel@tonic-gate 	/*
2950Sstevel@tonic-gate 	 * get rid of the devices pages
2960Sstevel@tonic-gate 	 */
2975331Samw 	(void) VOP_PUTPAGE(cvp, (offset_t)0, (uint_t)0, B_INVAL, CRED(), NULL);
2980Sstevel@tonic-gate 
2990Sstevel@tonic-gate 	/*
3000Sstevel@tonic-gate 	 * test 1 -- don't find nonexistant page
3010Sstevel@tonic-gate 	 */
3020Sstevel@tonic-gate 	test = 1;
3030Sstevel@tonic-gate 	if (pp = trans_trypage(cvp, 0))
3040Sstevel@tonic-gate 		goto errout;
3050Sstevel@tonic-gate 
3060Sstevel@tonic-gate 	/*
3070Sstevel@tonic-gate 	 * test 2 -- don't find busy page
3080Sstevel@tonic-gate 	 */
3090Sstevel@tonic-gate 	test = 2;
3100Sstevel@tonic-gate 	if ((pp = page_create(cvp, 0, 1, PG_WAIT)) == NULL)
3110Sstevel@tonic-gate 		goto errout;
3120Sstevel@tonic-gate 	if (trans_trypage(cvp, 0))
3130Sstevel@tonic-gate 		goto errout;
3140Sstevel@tonic-gate 	pvn_io_done(pp);
3150Sstevel@tonic-gate 	pp = 0;
3160Sstevel@tonic-gate 
3170Sstevel@tonic-gate 	/*
3180Sstevel@tonic-gate 	 * test 3 - find an idle page
3190Sstevel@tonic-gate 	 */
3200Sstevel@tonic-gate 	test = 3;
3210Sstevel@tonic-gate 	if ((pp = page_create(cvp, 0, 1, PG_WAIT)) == NULL)
3220Sstevel@tonic-gate 		goto errout;
3230Sstevel@tonic-gate 	pvn_io_done(pp);
3240Sstevel@tonic-gate 	if ((pp = trans_trypage(cvp, 0)) == NULL)
3250Sstevel@tonic-gate 		goto errout;
3260Sstevel@tonic-gate 	pvn_io_done(pp);
3270Sstevel@tonic-gate 	pp = 0;
3280Sstevel@tonic-gate 
3290Sstevel@tonic-gate 	test = 0;	/* no test failed */
3300Sstevel@tonic-gate errout:
3310Sstevel@tonic-gate 	if (pp)
3320Sstevel@tonic-gate 		pvn_io_done(pp);
3330Sstevel@tonic-gate 	/*
3340Sstevel@tonic-gate 	 * get rid of the file's pages
3350Sstevel@tonic-gate 	 */
3365331Samw 	(void) VOP_PUTPAGE(cvp, (offset_t)0, (uint_t)0, B_INVAL, CRED(), NULL);
3370Sstevel@tonic-gate 	VN_RELE(devvp);
3380Sstevel@tonic-gate 
3390Sstevel@tonic-gate 	migp->size = test;
3400Sstevel@tonic-gate 	if (test)
3410Sstevel@tonic-gate 		return (EINVAL);
3420Sstevel@tonic-gate 	return (0);
3430Sstevel@tonic-gate }
3440Sstevel@tonic-gate /*
3450Sstevel@tonic-gate  * TEST TSD
3460Sstevel@tonic-gate  */
3470Sstevel@tonic-gate #define	NKEYS		(7)
3480Sstevel@tonic-gate #define	NTSDTHREADS	(3)
3490Sstevel@tonic-gate struct tothread {
3500Sstevel@tonic-gate 	int		test;
3510Sstevel@tonic-gate 	int		error;
3520Sstevel@tonic-gate 	int		exits;
3530Sstevel@tonic-gate 	int		step;
3540Sstevel@tonic-gate 	kmutex_t	lock;
3550Sstevel@tonic-gate 	kcondvar_t	cv;
3560Sstevel@tonic-gate };
3570Sstevel@tonic-gate static uint_t		keys[NKEYS];
3580Sstevel@tonic-gate static struct tothread	tta[NTSDTHREADS];
3590Sstevel@tonic-gate static int		allocatorvalue;
3600Sstevel@tonic-gate static int		okdestructoralloc;
3610Sstevel@tonic-gate 
3620Sstevel@tonic-gate static void
trans_test_stepwait(struct tothread * tp,int step)3630Sstevel@tonic-gate trans_test_stepwait(struct tothread *tp, int step)
3640Sstevel@tonic-gate {
3650Sstevel@tonic-gate 	/*
3660Sstevel@tonic-gate 	 * wait for other thread
3670Sstevel@tonic-gate 	 */
3680Sstevel@tonic-gate 	mutex_enter(&tp->lock);
3690Sstevel@tonic-gate 	while (tp->step < step)
3700Sstevel@tonic-gate 		cv_wait(&tp->cv, &tp->lock);
3710Sstevel@tonic-gate 	mutex_exit(&tp->lock);
3720Sstevel@tonic-gate }
3730Sstevel@tonic-gate 
3740Sstevel@tonic-gate static void
trans_test_step(struct tothread * tp,int step)3750Sstevel@tonic-gate trans_test_step(struct tothread *tp, int step)
3760Sstevel@tonic-gate {
3770Sstevel@tonic-gate 	/*
3780Sstevel@tonic-gate 	 * wakeup other threads
3790Sstevel@tonic-gate 	 */
3800Sstevel@tonic-gate 	mutex_enter(&tp->lock);
3810Sstevel@tonic-gate 	tp->step = step;
3820Sstevel@tonic-gate 	cv_broadcast(&tp->cv);
3830Sstevel@tonic-gate 	mutex_exit(&tp->lock);
3840Sstevel@tonic-gate }
3850Sstevel@tonic-gate 
3860Sstevel@tonic-gate static void
trans_test_destructor(void * voidp)3870Sstevel@tonic-gate trans_test_destructor(void *voidp)
3880Sstevel@tonic-gate {
3890Sstevel@tonic-gate 	int		exits;
3900Sstevel@tonic-gate 	struct tothread	*tp	= voidp;
3910Sstevel@tonic-gate 
3920Sstevel@tonic-gate 	/*
3930Sstevel@tonic-gate 	 * check that threads clean up *all* TSD at exit
3940Sstevel@tonic-gate 	 */
3950Sstevel@tonic-gate 	mutex_enter(&tp->lock);
3960Sstevel@tonic-gate 	exits = ++tp->exits;
3970Sstevel@tonic-gate 	mutex_exit(&tp->lock);
3980Sstevel@tonic-gate 	if (exits >= NKEYS)
3990Sstevel@tonic-gate 		trans_test_step(tp, 3);
4000Sstevel@tonic-gate }
4010Sstevel@tonic-gate 
4020Sstevel@tonic-gate static void
trans_test_destructor_alloc(void * voidp)4030Sstevel@tonic-gate trans_test_destructor_alloc(void *voidp)
4040Sstevel@tonic-gate {
4050Sstevel@tonic-gate 	int	*value	= voidp;
4060Sstevel@tonic-gate 
4070Sstevel@tonic-gate 	okdestructoralloc = 0;
4080Sstevel@tonic-gate 	if (value) {
4090Sstevel@tonic-gate 		if (*value == allocatorvalue)
4100Sstevel@tonic-gate 			okdestructoralloc = 1;
4110Sstevel@tonic-gate 		md_trans_free((caddr_t)value, sizeof (value));
4120Sstevel@tonic-gate 	}
4130Sstevel@tonic-gate }
4140Sstevel@tonic-gate 
4150Sstevel@tonic-gate static void *
trans_test_allocator(void)4160Sstevel@tonic-gate trans_test_allocator(void)
4170Sstevel@tonic-gate {
4180Sstevel@tonic-gate 	int	*value;
4190Sstevel@tonic-gate 
4200Sstevel@tonic-gate 	value = (int *)md_trans_zalloc(sizeof (value));
4210Sstevel@tonic-gate 	*value = allocatorvalue;
4220Sstevel@tonic-gate 	return ((void *)value);
4230Sstevel@tonic-gate }
4240Sstevel@tonic-gate 
4250Sstevel@tonic-gate /*
4260Sstevel@tonic-gate  * thread used to test TSD destroy functionality
4270Sstevel@tonic-gate  */
4280Sstevel@tonic-gate static void
trans_test_thread(struct tothread * tp)4290Sstevel@tonic-gate trans_test_thread(struct tothread *tp)
4300Sstevel@tonic-gate {
4310Sstevel@tonic-gate 	int	i;
4320Sstevel@tonic-gate 	callb_cpr_t	cprinfo;
4330Sstevel@tonic-gate 
4340Sstevel@tonic-gate 	/*
4350Sstevel@tonic-gate 	 * Register cpr callback
4360Sstevel@tonic-gate 	 */
4370Sstevel@tonic-gate 	CALLB_CPR_INIT(&cprinfo, &tp->lock, callb_generic_cpr,
4380Sstevel@tonic-gate 	    "trans_test_thread");
4390Sstevel@tonic-gate 
4400Sstevel@tonic-gate 	/*
4410Sstevel@tonic-gate 	 * get some TSD
4420Sstevel@tonic-gate 	 */
4430Sstevel@tonic-gate 	for (i = NKEYS - 1; i >= 0; --i)
4440Sstevel@tonic-gate 		if (tsd_set(keys[i], tp)) {
4450Sstevel@tonic-gate 			tp->error = 500;
4460Sstevel@tonic-gate 			goto errout;
4470Sstevel@tonic-gate 		}
4480Sstevel@tonic-gate 	/*
4490Sstevel@tonic-gate 	 * tell parent that we have TSD
4500Sstevel@tonic-gate 	 */
4510Sstevel@tonic-gate 	trans_test_step(tp, 1);
4520Sstevel@tonic-gate 
4530Sstevel@tonic-gate 	/*
4540Sstevel@tonic-gate 	 * wait for parent to destroy some of our TSD
4550Sstevel@tonic-gate 	 */
4560Sstevel@tonic-gate 	trans_test_stepwait(tp, 2);
4570Sstevel@tonic-gate 
4580Sstevel@tonic-gate 	/*
4590Sstevel@tonic-gate 	 * make sure that the appropriate TSD was destroyed
4600Sstevel@tonic-gate 	 */
4610Sstevel@tonic-gate 	if ((tsd_get(keys[0]) != NULL) ||
4620Sstevel@tonic-gate 	    (tsd_get(keys[NKEYS-1]) != NULL) ||
4630Sstevel@tonic-gate 	    (tsd_get(keys[NKEYS>>1]) != NULL)) {
4640Sstevel@tonic-gate 		tp->error = 510;
4650Sstevel@tonic-gate 		goto errout;
4660Sstevel@tonic-gate 	}
4670Sstevel@tonic-gate 	for (i = 0; i < NKEYS; ++i)
4680Sstevel@tonic-gate 		if (tsd_get(keys[i]) != tp)
4690Sstevel@tonic-gate 			if (i != 0 && i != NKEYS - 1 && i != NKEYS >> 1) {
4700Sstevel@tonic-gate 				tp->error = 520;
4710Sstevel@tonic-gate 				goto errout;
4720Sstevel@tonic-gate 			}
4730Sstevel@tonic-gate 
4740Sstevel@tonic-gate 	/*
4750Sstevel@tonic-gate 	 * set up cpr exit
4760Sstevel@tonic-gate 	 */
4770Sstevel@tonic-gate 	mutex_enter(&tp->lock);
4780Sstevel@tonic-gate 	CALLB_CPR_EXIT(&cprinfo);
4790Sstevel@tonic-gate 	thread_exit();
4800Sstevel@tonic-gate errout:
4810Sstevel@tonic-gate 	/*
4820Sstevel@tonic-gate 	 * error -- make sure the parent will wake up (error code in tp)
4830Sstevel@tonic-gate 	 */
4840Sstevel@tonic-gate 	trans_test_step(tp, 3);
4850Sstevel@tonic-gate 
4860Sstevel@tonic-gate 	/*
4870Sstevel@tonic-gate 	 * set up cpr exit
4880Sstevel@tonic-gate 	 */
4890Sstevel@tonic-gate 	mutex_enter(&tp->lock);
4900Sstevel@tonic-gate 	CALLB_CPR_EXIT(&cprinfo);
4910Sstevel@tonic-gate 	thread_exit();
4920Sstevel@tonic-gate }
4930Sstevel@tonic-gate 
4940Sstevel@tonic-gate static void
trans_test_threadcreate(struct tothread * tp)4950Sstevel@tonic-gate trans_test_threadcreate(struct tothread *tp)
4960Sstevel@tonic-gate {
4970Sstevel@tonic-gate 	/*
4980Sstevel@tonic-gate 	 * initialize the per thread struct and make a thread
4990Sstevel@tonic-gate 	 */
5000Sstevel@tonic-gate 	bzero((caddr_t)tp, sizeof (struct tothread));
5010Sstevel@tonic-gate 
5020Sstevel@tonic-gate 	mutex_init(&tp->lock, NULL, MUTEX_DEFAULT, NULL);
5030Sstevel@tonic-gate 	cv_init(&tp->cv, NULL, CV_DEFAULT, NULL);
5040Sstevel@tonic-gate 
5050Sstevel@tonic-gate 	(void) thread_create(NULL, 0, trans_test_thread, tp, 0, &p0,
5060Sstevel@tonic-gate 	    TS_RUN, minclsyspri);
5070Sstevel@tonic-gate }
5080Sstevel@tonic-gate /*
5090Sstevel@tonic-gate  * driver for TSD tests -- *NOT REENTRANT*
5100Sstevel@tonic-gate  */
5110Sstevel@tonic-gate /*ARGSUSED1*/
5120Sstevel@tonic-gate static int
trans_test_tsd(void * d,int mode)5130Sstevel@tonic-gate trans_test_tsd(void *d, int mode)
5140Sstevel@tonic-gate {
5150Sstevel@tonic-gate 	int		test;
5160Sstevel@tonic-gate 	uint_t		rekeys[NKEYS];
5170Sstevel@tonic-gate 	int		i;
5180Sstevel@tonic-gate 	uint_t		key;
5190Sstevel@tonic-gate 	int		error;
5200Sstevel@tonic-gate 
5210Sstevel@tonic-gate 	md_i_get_t *migp = d;
5220Sstevel@tonic-gate 
5230Sstevel@tonic-gate 	mdclrerror(&migp->mde);
5240Sstevel@tonic-gate 	migp->size = 0;
5250Sstevel@tonic-gate 
5260Sstevel@tonic-gate 	/*
5270Sstevel@tonic-gate 	 * destroy old keys, if any
5280Sstevel@tonic-gate 	 */
5290Sstevel@tonic-gate 	for (i = 0; i < NKEYS; ++i)
5300Sstevel@tonic-gate 		tsd_destroy(&keys[i]);
5310Sstevel@tonic-gate 	/*
5320Sstevel@tonic-gate 	 * test 1 -- simple create and destroy keys tests
5330Sstevel@tonic-gate 	 */
5340Sstevel@tonic-gate 	test = 1;
5350Sstevel@tonic-gate 	error = 0;
5360Sstevel@tonic-gate 	for (i = 0; i < NKEYS; ++i) {
5370Sstevel@tonic-gate 		tsd_create(&keys[i], NULL);
5380Sstevel@tonic-gate 
5390Sstevel@tonic-gate 		/* get with no set should return NULL */
5400Sstevel@tonic-gate 		if (tsd_get(keys[i]) != NULL) {
5410Sstevel@tonic-gate 			error = 100;
5420Sstevel@tonic-gate 			goto errout;
5430Sstevel@tonic-gate 		}
5440Sstevel@tonic-gate 
5450Sstevel@tonic-gate 		/* destroyed key should be 0 */
5460Sstevel@tonic-gate 		key = keys[i];
5470Sstevel@tonic-gate 		tsd_destroy(&keys[i]);
5480Sstevel@tonic-gate 		if (keys[i]) {
5490Sstevel@tonic-gate 			error = 110;
5500Sstevel@tonic-gate 			goto errout;
5510Sstevel@tonic-gate 		}
5520Sstevel@tonic-gate 
5530Sstevel@tonic-gate 		/* destroy the key twice */
5540Sstevel@tonic-gate 		keys[i] = key;
5550Sstevel@tonic-gate 		tsd_destroy(&keys[i]);
5560Sstevel@tonic-gate 
5570Sstevel@tonic-gate 		/* destroyed key should be 0 */
5580Sstevel@tonic-gate 		if (keys[i]) {
5590Sstevel@tonic-gate 			error = 120;
5600Sstevel@tonic-gate 			goto errout;
5610Sstevel@tonic-gate 		}
5620Sstevel@tonic-gate 
5630Sstevel@tonic-gate 		/* getting a destroyed key should return NULL */
5640Sstevel@tonic-gate 		if (tsd_get(keys[i]) != NULL) {
5650Sstevel@tonic-gate 			error = 130;
5660Sstevel@tonic-gate 			goto errout;
5670Sstevel@tonic-gate 		}
5680Sstevel@tonic-gate 		/* recreate the key */
5690Sstevel@tonic-gate 		tsd_create(&keys[i], NULL);
5700Sstevel@tonic-gate 
5710Sstevel@tonic-gate 		/* should be the same key as before */
5720Sstevel@tonic-gate 		if (key != keys[i]) {
5730Sstevel@tonic-gate 			error = 140;
5740Sstevel@tonic-gate 			goto errout;
5750Sstevel@tonic-gate 		}
5760Sstevel@tonic-gate 
5770Sstevel@tonic-gate 		/* initial value should be NULL */
5780Sstevel@tonic-gate 		if (tsd_get(keys[i]) != NULL) {
5790Sstevel@tonic-gate 			error = 150;
5800Sstevel@tonic-gate 			goto errout;
5810Sstevel@tonic-gate 		}
5820Sstevel@tonic-gate 
5830Sstevel@tonic-gate 		/* cleanup */
5840Sstevel@tonic-gate 		tsd_destroy(&keys[i]);
5850Sstevel@tonic-gate 	}
5860Sstevel@tonic-gate 
5870Sstevel@tonic-gate 	/*
5880Sstevel@tonic-gate 	 * test 2 -- recreate keys
5890Sstevel@tonic-gate 	 */
5900Sstevel@tonic-gate 	test = 2;
5910Sstevel@tonic-gate 	error = 0;
5920Sstevel@tonic-gate 	for (i = 0; i < NKEYS; ++i)
5930Sstevel@tonic-gate 		tsd_create(&keys[i], NULL);
5940Sstevel@tonic-gate 	for (i = 0; i < NKEYS; ++i) {
5950Sstevel@tonic-gate 		/* make sure the keys were created */
5960Sstevel@tonic-gate 		if (keys[i] == 0) {
5970Sstevel@tonic-gate 			error = 200;
5980Sstevel@tonic-gate 			goto errout;
5990Sstevel@tonic-gate 		}
6000Sstevel@tonic-gate 
6010Sstevel@tonic-gate 		/* make sure that recreating key doesn't change it */
6020Sstevel@tonic-gate 		rekeys[i] = keys[i];
6030Sstevel@tonic-gate 		tsd_create(&rekeys[i], NULL);
6040Sstevel@tonic-gate 		if (rekeys[i] != keys[i]) {
6050Sstevel@tonic-gate 			error = 210;
6060Sstevel@tonic-gate 			goto errout;
6070Sstevel@tonic-gate 		}
6080Sstevel@tonic-gate 	}
6090Sstevel@tonic-gate 	for (i = 0; i < NKEYS; ++i)
6100Sstevel@tonic-gate 		tsd_destroy(&keys[i]);
6110Sstevel@tonic-gate 
6120Sstevel@tonic-gate 	/*
6130Sstevel@tonic-gate 	 * test 3 -- check processing for unset and destroyed keys
6140Sstevel@tonic-gate 	 */
6150Sstevel@tonic-gate 	test = 3;
6160Sstevel@tonic-gate 	error = 0;
6170Sstevel@tonic-gate 
6180Sstevel@tonic-gate 	/* getting a 0 key returns NULL */
6190Sstevel@tonic-gate 	if (tsd_get(0) != NULL) {
6200Sstevel@tonic-gate 		error = 300;
6210Sstevel@tonic-gate 		goto errout;
6220Sstevel@tonic-gate 	}
6230Sstevel@tonic-gate 
6240Sstevel@tonic-gate 	/* setting a 0 key returns error */
6250Sstevel@tonic-gate 	if (tsd_set(0, NULL) != EINVAL) {
6260Sstevel@tonic-gate 		error = 310;
6270Sstevel@tonic-gate 		goto errout;
6280Sstevel@tonic-gate 	}
6290Sstevel@tonic-gate 	tsd_create(&key, NULL);
6300Sstevel@tonic-gate 
6310Sstevel@tonic-gate 	/* setting a created key returns no error */
6320Sstevel@tonic-gate 	if (tsd_set(key, NULL) == EINVAL) {
6330Sstevel@tonic-gate 		error = 320;
6340Sstevel@tonic-gate 		goto errout;
6350Sstevel@tonic-gate 	}
6360Sstevel@tonic-gate 	tsd_destroy(&key);
6370Sstevel@tonic-gate 
6380Sstevel@tonic-gate 	/* setting a destroyed key returns error */
6390Sstevel@tonic-gate 	if (tsd_set(key, NULL) != EINVAL) {
6400Sstevel@tonic-gate 		error = 330;
6410Sstevel@tonic-gate 		goto errout;
6420Sstevel@tonic-gate 	}
6430Sstevel@tonic-gate 
6440Sstevel@tonic-gate 	/*
6450Sstevel@tonic-gate 	 * test 4 -- make sure that set and get work
6460Sstevel@tonic-gate 	 */
6470Sstevel@tonic-gate 	test = 4;
6480Sstevel@tonic-gate 	error = 0;
6490Sstevel@tonic-gate 
6500Sstevel@tonic-gate 	for (i = 0; i < NKEYS; ++i) {
6510Sstevel@tonic-gate 		tsd_create(&keys[i], NULL);
6520Sstevel@tonic-gate 
6530Sstevel@tonic-gate 		/* set a value */
6540Sstevel@tonic-gate 		(void) tsd_set(keys[i], &key);
6550Sstevel@tonic-gate 
6560Sstevel@tonic-gate 		/* get the value */
6570Sstevel@tonic-gate 		if (tsd_get(keys[i]) != &key) {
6580Sstevel@tonic-gate 			error = 400;
6590Sstevel@tonic-gate 			goto errout;
6600Sstevel@tonic-gate 		}
6610Sstevel@tonic-gate 
6620Sstevel@tonic-gate 		/* set the value to NULL */
6630Sstevel@tonic-gate 		(void) tsd_set(keys[i], NULL);
6640Sstevel@tonic-gate 
6650Sstevel@tonic-gate 		/* get the NULL */
6660Sstevel@tonic-gate 		if (tsd_get(keys[i]) != NULL) {
6670Sstevel@tonic-gate 			error = 410;
6680Sstevel@tonic-gate 			goto errout;
6690Sstevel@tonic-gate 		}
6700Sstevel@tonic-gate 	}
6710Sstevel@tonic-gate 	/* cleanup */
6720Sstevel@tonic-gate 	for (i = 0; i < NKEYS; ++i)
6730Sstevel@tonic-gate 		tsd_destroy(&keys[i]);
6740Sstevel@tonic-gate 
6750Sstevel@tonic-gate 	/*
6760Sstevel@tonic-gate 	 * test 5 -- destroying keys w/multiple threads
6770Sstevel@tonic-gate 	 */
6780Sstevel@tonic-gate 	test = 5;
6790Sstevel@tonic-gate 	error = 0;
6800Sstevel@tonic-gate 
6810Sstevel@tonic-gate 	/* create the keys */
6820Sstevel@tonic-gate 	for (i = 0; i < NKEYS; ++i)
6830Sstevel@tonic-gate 		tsd_create(&keys[i], trans_test_destructor);
6840Sstevel@tonic-gate 
6850Sstevel@tonic-gate 	/* create some threads */
6860Sstevel@tonic-gate 	for (i = 0; i < NTSDTHREADS; ++i)
6870Sstevel@tonic-gate 		trans_test_threadcreate(&tta[i]);
6880Sstevel@tonic-gate 
6890Sstevel@tonic-gate 	/* wait for the threads to assign TSD */
6900Sstevel@tonic-gate 	for (i = 0; i < NTSDTHREADS; ++i)
6910Sstevel@tonic-gate 		trans_test_stepwait(&tta[i], 1);
6920Sstevel@tonic-gate 
6930Sstevel@tonic-gate 	/* destroy some of the keys */
6940Sstevel@tonic-gate 	tsd_destroy(&keys[0]);
6950Sstevel@tonic-gate 	tsd_destroy(&keys[NKEYS - 1]);
6960Sstevel@tonic-gate 	tsd_destroy(&keys[NKEYS >> 1]);
6970Sstevel@tonic-gate 	tsd_destroy(&keys[NKEYS >> 1]);
6980Sstevel@tonic-gate 
6990Sstevel@tonic-gate 	/* wakeup the threads -- they check that the destroy took */
7000Sstevel@tonic-gate 	for (i = 0; i < NTSDTHREADS; ++i)
7010Sstevel@tonic-gate 		trans_test_step(&tta[i], 2);
7020Sstevel@tonic-gate 
7030Sstevel@tonic-gate 	/* wait for the threads to exit (also checks for TSD cleanup) */
7040Sstevel@tonic-gate 	for (i = 0; i < NTSDTHREADS; ++i)
7050Sstevel@tonic-gate 		trans_test_stepwait(&tta[i], 3);
7060Sstevel@tonic-gate 
7070Sstevel@tonic-gate 	/* destroy the rest of the keys */
7080Sstevel@tonic-gate 	for (i = 0; i < NKEYS; ++i)
7090Sstevel@tonic-gate 		tsd_destroy(&keys[i]);
7100Sstevel@tonic-gate 
7110Sstevel@tonic-gate 	/* check for error */
7120Sstevel@tonic-gate 	for (i = 0; i < NTSDTHREADS; ++i) {
7130Sstevel@tonic-gate 		if (!error)
7140Sstevel@tonic-gate 			error = tta[i].error;
7150Sstevel@tonic-gate 		mutex_destroy(&tta[i].lock);
7160Sstevel@tonic-gate 		cv_destroy(&tta[i].cv);
7170Sstevel@tonic-gate 	}
7180Sstevel@tonic-gate 
7190Sstevel@tonic-gate 	/*
7200Sstevel@tonic-gate 	 * test 6 -- test getcreate
7210Sstevel@tonic-gate 	 */
7220Sstevel@tonic-gate 	test = 6;
7230Sstevel@tonic-gate 	error = 0;
7240Sstevel@tonic-gate 
7250Sstevel@tonic-gate 	/* make sure the keys are destroyed */
7260Sstevel@tonic-gate 	for (i = 0; i < NKEYS; ++i)
7270Sstevel@tonic-gate 		tsd_destroy(&keys[i]);
7280Sstevel@tonic-gate 
7290Sstevel@tonic-gate 	/* get w/create */
7300Sstevel@tonic-gate 	for (i = 0; i < NKEYS; ++i) {
7310Sstevel@tonic-gate 		allocatorvalue = i;
7320Sstevel@tonic-gate 		if (*(int *)tsd_getcreate(&keys[i], trans_test_destructor_alloc,
7337563SPrasad.Singamsetty@Sun.COM 		    trans_test_allocator) != allocatorvalue) {
7340Sstevel@tonic-gate 			error = 600;
7350Sstevel@tonic-gate 			goto errout;
7360Sstevel@tonic-gate 		}
7370Sstevel@tonic-gate 	}
7380Sstevel@tonic-gate 	for (i = 0; i < NKEYS; ++i) {
7390Sstevel@tonic-gate 		allocatorvalue = i;
7400Sstevel@tonic-gate 		if (*(int *)tsd_get(keys[i]) != allocatorvalue) {
7410Sstevel@tonic-gate 			error = 610;
7420Sstevel@tonic-gate 			goto errout;
7430Sstevel@tonic-gate 		}
7440Sstevel@tonic-gate 	}
7450Sstevel@tonic-gate 	/* make sure destructor gets called when we destroy the keys */
7460Sstevel@tonic-gate 	for (i = 0; i < NKEYS; ++i) {
7470Sstevel@tonic-gate 		allocatorvalue = i;
7480Sstevel@tonic-gate 		okdestructoralloc = 0;
7490Sstevel@tonic-gate 		tsd_destroy(&keys[i]);
7500Sstevel@tonic-gate 		if (okdestructoralloc == 0) {
7510Sstevel@tonic-gate 			error = 620;
7520Sstevel@tonic-gate 			goto errout;
7530Sstevel@tonic-gate 		}
7540Sstevel@tonic-gate 	}
7550Sstevel@tonic-gate 
7560Sstevel@tonic-gate errout:
7570Sstevel@tonic-gate 	/* make sure the keys are destroyed */
7580Sstevel@tonic-gate 	for (i = 0; i < NKEYS; ++i)
7590Sstevel@tonic-gate 		tsd_destroy(&keys[i]);
7600Sstevel@tonic-gate 
7610Sstevel@tonic-gate 	/* return test # and error code (if any) */
7620Sstevel@tonic-gate 	migp->size = test;
7630Sstevel@tonic-gate 	return (error);
7640Sstevel@tonic-gate }
7650Sstevel@tonic-gate 
7660Sstevel@tonic-gate /*
7670Sstevel@tonic-gate  * Error Injection Structures, Data, and Functions:
7680Sstevel@tonic-gate  *
7690Sstevel@tonic-gate  * Error injection is used to test the Harpy error recovery system.  The
7700Sstevel@tonic-gate  * MD_IOC_INJECTERRORS ioctl is used to start or continue error injection on a
7710Sstevel@tonic-gate  * unit, and MD_IOC_STOPERRORS turns it off.  An mt_error structure is
7720Sstevel@tonic-gate  * associated with every trans device for which we are injecting errors.  When
7730Sstevel@tonic-gate  * MD_IOC_INJECTERRORS is issued, mdv_strategy_tstpnt is set to point to
7740Sstevel@tonic-gate  * trans_error_injector(), so that it gets called for every MDD I/O operation.
7750Sstevel@tonic-gate  *
7760Sstevel@tonic-gate  * The trans unit can be in one of three states:
7770Sstevel@tonic-gate  *
7780Sstevel@tonic-gate  *	count down -	Each I/O causes er_count_down to be decremented.
7790Sstevel@tonic-gate  *			When er_count_down reaches 0, an error is injected,
7800Sstevel@tonic-gate  *			the block number is remembered.  Without makeing
7810Sstevel@tonic-gate  *			special provisions, the log area would receive a
7820Sstevel@tonic-gate  *			small percentage of the injected errors.  Thus,
7830Sstevel@tonic-gate  *			trans_check_error() will be written, so that every
7840Sstevel@tonic-gate  *			other error is injected on the log.
7850Sstevel@tonic-gate  *
7860Sstevel@tonic-gate  *	suspend -	No errors are generated and the counters are not
7870Sstevel@tonic-gate  *			modified.  This is so that fsck/mkfs can do their thing
7880Sstevel@tonic-gate  *			(we're not testing them) and so that the test script can
7890Sstevel@tonic-gate  *			set up another test.  The transition back to the count
7900Sstevel@tonic-gate  *			down state occurs when MD_IOC_INJECTERRORS is invoked
7910Sstevel@tonic-gate  *			again.
7920Sstevel@tonic-gate  */
7930Sstevel@tonic-gate 
7940Sstevel@tonic-gate typedef enum {
7950Sstevel@tonic-gate 	mte_count_down,
7960Sstevel@tonic-gate 	mte_suspend,
7970Sstevel@tonic-gate 	mte_watch_block
7980Sstevel@tonic-gate } mte_state;
7990Sstevel@tonic-gate 
8000Sstevel@tonic-gate typedef struct mt_error {
8010Sstevel@tonic-gate 	struct mt_error	*er_next;	/* next error unit in list. */
8020Sstevel@tonic-gate 	mte_state	er_state;
8030Sstevel@tonic-gate 	mt_unit_t	*er_unitp;	/* unit to force errors on. */
8040Sstevel@tonic-gate 	size_t		er_count_down;	/* i/o transactions until error. */
8050Sstevel@tonic-gate 	size_t		er_increment;	/* increment for reset_count. */
8060Sstevel@tonic-gate 	size_t		er_reset_count;	/* used to reset er_count_down */
8070Sstevel@tonic-gate 	size_t		er_total_errors; /* count generated errors. */
8080Sstevel@tonic-gate 	/* Following fields describe error we are injecting. */
8090Sstevel@tonic-gate 	dev_t		er_bad_unit;	/* Unit associated with block in */
8100Sstevel@tonic-gate 					/* error. */
8110Sstevel@tonic-gate 	off_t		er_bad_block;	/* Block in error. */
8120Sstevel@tonic-gate } mt_error_t;
8130Sstevel@tonic-gate 
8140Sstevel@tonic-gate #define	ERROR_INCREMENT	(1)
8150Sstevel@tonic-gate #define	INITIAL_COUNT	(1)
8160Sstevel@tonic-gate 
8170Sstevel@tonic-gate static int		default_increment	= ERROR_INCREMENT;
8180Sstevel@tonic-gate static kmutex_t		error_mutex;	/* protects error_list */
8190Sstevel@tonic-gate static mt_error_t	error_list_head;
8200Sstevel@tonic-gate static int		initial_count		= INITIAL_COUNT;
8210Sstevel@tonic-gate static int		(*tstpnt_save)(buf_t *, int, void*) = NULL;
8220Sstevel@tonic-gate 
8230Sstevel@tonic-gate static mt_error_t *
find_by_mtunit(mt_unit_t * un,mt_error_t ** pred_errp)8240Sstevel@tonic-gate find_by_mtunit(mt_unit_t *un, mt_error_t **pred_errp)
8250Sstevel@tonic-gate {
8260Sstevel@tonic-gate 	mt_error_t	*errp	= (mt_error_t *)NULL;
8270Sstevel@tonic-gate 
8280Sstevel@tonic-gate 	ASSERT(mutex_owned(&error_mutex) != 0);
8290Sstevel@tonic-gate 	*pred_errp = &error_list_head;
8300Sstevel@tonic-gate 	while ((errp = (*pred_errp)->er_next) != (mt_error_t *)NULL) {
8310Sstevel@tonic-gate 		if (errp->er_unitp == un)
8320Sstevel@tonic-gate 			break;
8330Sstevel@tonic-gate 		*pred_errp = errp;
8340Sstevel@tonic-gate 	}
8350Sstevel@tonic-gate 	return (errp);
8360Sstevel@tonic-gate }
8370Sstevel@tonic-gate 
8380Sstevel@tonic-gate static mt_error_t *
find_by_dev(md_dev64_t dev)8390Sstevel@tonic-gate find_by_dev(md_dev64_t dev)
8400Sstevel@tonic-gate {
8410Sstevel@tonic-gate 	mt_error_t	*errp	= &error_list_head;
8420Sstevel@tonic-gate 
8430Sstevel@tonic-gate 	ASSERT(mutex_owned(&error_mutex) != 0);
8440Sstevel@tonic-gate 	while ((errp = errp->er_next) != (mt_error_t *)NULL) {
8450Sstevel@tonic-gate 		if ((errp->er_unitp->un_m_dev == dev) ||
8467563SPrasad.Singamsetty@Sun.COM 		    (errp->er_unitp->un_l_dev == dev))
8470Sstevel@tonic-gate 			break;
8480Sstevel@tonic-gate 	}
8490Sstevel@tonic-gate 	return (errp);
8500Sstevel@tonic-gate }
8510Sstevel@tonic-gate 
8520Sstevel@tonic-gate static int
trans_check_error(buf_t * bp,mt_error_t * errp)8530Sstevel@tonic-gate trans_check_error(buf_t *bp, mt_error_t *errp)
8540Sstevel@tonic-gate {
8550Sstevel@tonic-gate 	int		rv	= 0;
8560Sstevel@tonic-gate 	md_dev64_t	target	= md_expldev(bp->b_edev);
8570Sstevel@tonic-gate 
8580Sstevel@tonic-gate 	ASSERT(mutex_owned(&error_mutex) != 0);
8590Sstevel@tonic-gate 	switch (errp->er_state) {
8600Sstevel@tonic-gate 	case mte_count_down:
8610Sstevel@tonic-gate 		errp->er_count_down--;
8620Sstevel@tonic-gate 		if (errp->er_count_down == 0) {
8630Sstevel@tonic-gate 			/*
8640Sstevel@tonic-gate 			 * Every other error that we inject should be on
8650Sstevel@tonic-gate 			 * the log device.  Errors will be injected on the
8660Sstevel@tonic-gate 			 * log device when errp->er_total_errors is even
8670Sstevel@tonic-gate 			 * and on the master device when it is odd.  If
8680Sstevel@tonic-gate 			 * this I/O is not for the appropriate device, we
8690Sstevel@tonic-gate 			 * will set errp->er_count_down to 1, so that we
8700Sstevel@tonic-gate 			 * can try again later.
8710Sstevel@tonic-gate 			 */
8720Sstevel@tonic-gate 			if ((((errp->er_total_errors % 2) == 0) &&
8737563SPrasad.Singamsetty@Sun.COM 			    (errp->er_unitp->un_l_dev == target)) ||
8747563SPrasad.Singamsetty@Sun.COM 			    (((errp->er_total_errors % 2) != 0) &&
8757563SPrasad.Singamsetty@Sun.COM 			    (errp->er_unitp->un_m_dev == target))) {
8760Sstevel@tonic-gate 				/* simulate an error */
8770Sstevel@tonic-gate 				bp->b_flags |= B_ERROR;
8780Sstevel@tonic-gate 				bp->b_error = EIO;
8790Sstevel@tonic-gate 				/* remember the error. */
8800Sstevel@tonic-gate 				errp->er_total_errors++;
8810Sstevel@tonic-gate 				errp->er_bad_unit = bp->b_edev;
8820Sstevel@tonic-gate 				errp->er_bad_block = bp->b_blkno;
8830Sstevel@tonic-gate 				/* reset counters. */
8840Sstevel@tonic-gate 				errp->er_count_down = errp->er_reset_count;
8850Sstevel@tonic-gate 				errp->er_reset_count += errp->er_increment;
8860Sstevel@tonic-gate 				rv = 1;
8870Sstevel@tonic-gate 			} else {
8880Sstevel@tonic-gate 				/* Try again next time. */
8890Sstevel@tonic-gate 				errp->er_count_down = 1;
8900Sstevel@tonic-gate 			}
8910Sstevel@tonic-gate 		}
8920Sstevel@tonic-gate 		break;
8930Sstevel@tonic-gate 
8940Sstevel@tonic-gate 	case mte_suspend:
8950Sstevel@tonic-gate 		/* No errors while suspended. */
8960Sstevel@tonic-gate 		break;
8970Sstevel@tonic-gate 
8980Sstevel@tonic-gate 	case mte_watch_block:
8990Sstevel@tonic-gate 		if ((bp->b_edev == errp->er_bad_unit) &&
9007563SPrasad.Singamsetty@Sun.COM 		    (bp->b_blkno == errp->er_bad_block)) {
9010Sstevel@tonic-gate 			bp->b_flags |= B_ERROR;
9020Sstevel@tonic-gate 			bp->b_error = EIO;
9030Sstevel@tonic-gate 			rv = 1;
9040Sstevel@tonic-gate 		}
9050Sstevel@tonic-gate 		break;
9060Sstevel@tonic-gate 	}
9070Sstevel@tonic-gate 	return (rv);
9080Sstevel@tonic-gate }
9090Sstevel@tonic-gate 
9100Sstevel@tonic-gate static int
trans_error_injector(buf_t * bp,int flag,void * private)9110Sstevel@tonic-gate trans_error_injector(buf_t *bp, int flag, void* private)
9120Sstevel@tonic-gate {
9130Sstevel@tonic-gate 	mt_error_t	*errp	= (mt_error_t *)NULL;
9140Sstevel@tonic-gate 	int		(*tstpnt)(buf_t *, int, void*) = NULL;
9150Sstevel@tonic-gate 	int		rv	= 0;
9160Sstevel@tonic-gate 	md_dev64_t	target	= md_expldev(bp->b_edev);
9170Sstevel@tonic-gate 	int		trv	= 0;
9180Sstevel@tonic-gate 	mt_unit_t	*un;
9190Sstevel@tonic-gate 
9200Sstevel@tonic-gate 	mutex_enter(&error_mutex);
9210Sstevel@tonic-gate 	errp = find_by_dev(target);
9220Sstevel@tonic-gate 	if (errp != (mt_error_t *)NULL) {
9230Sstevel@tonic-gate 		un = errp->er_unitp;
9240Sstevel@tonic-gate 		if (target == un->un_m_dev) {
9250Sstevel@tonic-gate 			/* Target is our master device. */
9260Sstevel@tonic-gate 			rv = trans_check_error(bp, errp);
9270Sstevel@tonic-gate 		}
9280Sstevel@tonic-gate 		if (target == un->un_l_dev) {
9290Sstevel@tonic-gate 			/*
9300Sstevel@tonic-gate 			 * Target is our log device.  Unfortunately, the same
9310Sstevel@tonic-gate 			 * device may also be used for the MDD database.
9320Sstevel@tonic-gate 			 * Therefore, we need to make sure that the I/O is for
9330Sstevel@tonic-gate 			 * the range of blocks designated as our log.
9340Sstevel@tonic-gate 			 */
9350Sstevel@tonic-gate 			if ((bp->b_blkno >= un->un_l_pwsblk) &&
9367563SPrasad.Singamsetty@Sun.COM 			    ((bp->b_blkno + btodb(bp->b_bcount)) <=
9377563SPrasad.Singamsetty@Sun.COM 			    (un->un_l_sblk + un->un_l_tblks))) {
9380Sstevel@tonic-gate 				rv = trans_check_error(bp, errp);
9390Sstevel@tonic-gate 			}
9400Sstevel@tonic-gate 		}
9410Sstevel@tonic-gate 	}
9420Sstevel@tonic-gate 	tstpnt = tstpnt_save;
9430Sstevel@tonic-gate 	mutex_exit(&error_mutex);
9440Sstevel@tonic-gate 
9450Sstevel@tonic-gate 	if (tstpnt != NULL)
9460Sstevel@tonic-gate 		trv = (*tstpnt)(bp, flag, private);
9470Sstevel@tonic-gate 
9480Sstevel@tonic-gate 	/*
9490Sstevel@tonic-gate 	 * If we are producing an error (rv != 0) we need to make sure that
9500Sstevel@tonic-gate 	 * biodone gets called.  If the tstpnt returned non-zero,
9510Sstevel@tonic-gate 	 * we'll assume that it called biodone.
9520Sstevel@tonic-gate 	 */
9530Sstevel@tonic-gate 	if ((rv != 0) && (trv == 0)) {
9540Sstevel@tonic-gate 		md_biodone(bp);
9550Sstevel@tonic-gate 	}
9560Sstevel@tonic-gate 	rv = ((rv == 0) && (trv == 0)) ? 0 : 1;
9570Sstevel@tonic-gate 	return (rv);
9580Sstevel@tonic-gate }
9590Sstevel@tonic-gate 
9600Sstevel@tonic-gate /*
9610Sstevel@tonic-gate  * Prepare to inject errors on the master and log devices associated with the
9620Sstevel@tonic-gate  * unit specified in migp.  The first time that trans_inject_errors() is called
9630Sstevel@tonic-gate  * for a unit, an mt_error_t structure is allocated and initialized for the
9640Sstevel@tonic-gate  * unit.  Subsequent calls for the unit will just insure that the unit is in the
9650Sstevel@tonic-gate  * count down state.
9660Sstevel@tonic-gate  *
9670Sstevel@tonic-gate  * If an mt_error structure is allocated and it is the first one to be put in
9680Sstevel@tonic-gate  * the list, mdv_strategy_tstpnt (which is referenced in md_call_strategy()) is
9690Sstevel@tonic-gate  * set to trans_error_injector so that it will be called to see if an I/O
9700Sstevel@tonic-gate  * request should be treated as an error.
9710Sstevel@tonic-gate  */
9720Sstevel@tonic-gate 
9730Sstevel@tonic-gate /*ARGSUSED1*/
9740Sstevel@tonic-gate static int
trans_inject_errors(void * d,int mode,IOLOCK * lock)9750Sstevel@tonic-gate trans_inject_errors(void *d, int mode, IOLOCK *lock)
9760Sstevel@tonic-gate {
9770Sstevel@tonic-gate 	mt_error_t	*errp;
9780Sstevel@tonic-gate 	mt_error_t	*do_not_care;
9790Sstevel@tonic-gate 	mt_unit_t	*un;
9800Sstevel@tonic-gate 	int		rv = 0;
9810Sstevel@tonic-gate 
9820Sstevel@tonic-gate 	md_i_get_t *migp = d;
9830Sstevel@tonic-gate 
9840Sstevel@tonic-gate 	mdclrerror(&migp->mde);
9850Sstevel@tonic-gate 
9860Sstevel@tonic-gate 	un = trans_getun(migp->id, &migp->mde,
9877563SPrasad.Singamsetty@Sun.COM 	    RD_LOCK, lock);
9880Sstevel@tonic-gate 	if (un == NULL)
9890Sstevel@tonic-gate 		return (EINVAL);
9900Sstevel@tonic-gate 
9910Sstevel@tonic-gate 	/*
9920Sstevel@tonic-gate 	 * If there is already a an error structure for the unit make sure that
9930Sstevel@tonic-gate 	 * it is in count down mode.
9940Sstevel@tonic-gate 	 */
9950Sstevel@tonic-gate 
9960Sstevel@tonic-gate 	mutex_enter(&error_mutex);
9970Sstevel@tonic-gate 	errp = find_by_mtunit(un, &do_not_care);
9980Sstevel@tonic-gate 	if (errp != (mt_error_t *)NULL) {
9990Sstevel@tonic-gate 		errp->er_state = mte_count_down;
10000Sstevel@tonic-gate 	} else {
10010Sstevel@tonic-gate 
10020Sstevel@tonic-gate 		/*
10030Sstevel@tonic-gate 		 * Initialize error structure.
10040Sstevel@tonic-gate 		 */
10050Sstevel@tonic-gate 
10060Sstevel@tonic-gate 		errp = (mt_error_t *)md_trans_zalloc(sizeof (mt_error_t));
10070Sstevel@tonic-gate 		errp->er_state = mte_count_down;
10080Sstevel@tonic-gate 		errp->er_unitp = un;
10090Sstevel@tonic-gate 		errp->er_count_down = initial_count;
10100Sstevel@tonic-gate 		errp->er_increment = default_increment;
10110Sstevel@tonic-gate 		errp->er_reset_count = initial_count;
10120Sstevel@tonic-gate 		errp->er_total_errors = 0;
10130Sstevel@tonic-gate 		errp->er_bad_unit = 0;
10140Sstevel@tonic-gate 		errp->er_bad_block = 0;
10150Sstevel@tonic-gate 
10160Sstevel@tonic-gate 		/* Insert it into the list. */
10170Sstevel@tonic-gate 
10180Sstevel@tonic-gate 		errp->er_next = error_list_head.er_next;
10190Sstevel@tonic-gate 		error_list_head.er_next = errp;
10200Sstevel@tonic-gate 
10210Sstevel@tonic-gate 		/*
10220Sstevel@tonic-gate 		 * Set up md_call_strategy to call our error injector.
10230Sstevel@tonic-gate 		 */
10240Sstevel@tonic-gate 
10250Sstevel@tonic-gate 		if (mdv_strategy_tstpnt != trans_error_injector) {
10260Sstevel@tonic-gate 			tstpnt_save = mdv_strategy_tstpnt;
10270Sstevel@tonic-gate 			mdv_strategy_tstpnt = trans_error_injector;
10280Sstevel@tonic-gate 		}
10290Sstevel@tonic-gate 	}
10300Sstevel@tonic-gate 	mutex_exit(&error_mutex);
10310Sstevel@tonic-gate 	return (rv);
10320Sstevel@tonic-gate }
10330Sstevel@tonic-gate 
10340Sstevel@tonic-gate /*ARGSUSED1*/
10350Sstevel@tonic-gate static int
trans_stop_errors(void * d,int mode,IOLOCK * lock)10360Sstevel@tonic-gate trans_stop_errors(void *d, int mode, IOLOCK *lock)
10370Sstevel@tonic-gate {
10380Sstevel@tonic-gate 	mt_error_t	*errp	= (mt_error_t *)NULL;
10390Sstevel@tonic-gate 	mt_error_t	*pred_errp;
10400Sstevel@tonic-gate 	mt_unit_t	*un;
10410Sstevel@tonic-gate 	int		rv	= 0;
10420Sstevel@tonic-gate 
10430Sstevel@tonic-gate 	md_i_get_t *migp = d;
10440Sstevel@tonic-gate 
10450Sstevel@tonic-gate 	mdclrerror(&migp->mde);
10460Sstevel@tonic-gate 
10470Sstevel@tonic-gate 	un = trans_getun(migp->id, &migp->mde,
10487563SPrasad.Singamsetty@Sun.COM 	    RD_LOCK, lock);
10490Sstevel@tonic-gate 	if (un == NULL)
10500Sstevel@tonic-gate 		return (EINVAL);
10510Sstevel@tonic-gate 
10520Sstevel@tonic-gate 	mutex_enter(&error_mutex);
10530Sstevel@tonic-gate 	errp = find_by_mtunit(un, &pred_errp);
10540Sstevel@tonic-gate 	if (errp != (mt_error_t *)NULL) {
10550Sstevel@tonic-gate 		/* Remove from list. */
10560Sstevel@tonic-gate 		pred_errp->er_next = errp->er_next;
10570Sstevel@tonic-gate 		if ((error_list_head.er_next == (mt_error_t *)NULL) &&
10587563SPrasad.Singamsetty@Sun.COM 		    (mdv_strategy_tstpnt == trans_error_injector)) {
10590Sstevel@tonic-gate 			mdv_strategy_tstpnt = tstpnt_save;
10600Sstevel@tonic-gate 		}
10610Sstevel@tonic-gate 	} else {
10620Sstevel@tonic-gate 		/* unit not set up for errors. */
10630Sstevel@tonic-gate 		rv = ENXIO;
10640Sstevel@tonic-gate 	}
10650Sstevel@tonic-gate 	mutex_exit(&error_mutex);
10660Sstevel@tonic-gate 
10670Sstevel@tonic-gate 	/* Free memory. */
10680Sstevel@tonic-gate 
10690Sstevel@tonic-gate 	if (errp != (mt_error_t *)NULL) {
10700Sstevel@tonic-gate 		md_trans_free((void *)errp, sizeof (*errp));
10710Sstevel@tonic-gate 	}
10720Sstevel@tonic-gate 	return (rv);
10730Sstevel@tonic-gate }
10740Sstevel@tonic-gate 
10750Sstevel@tonic-gate int
_init_ioctl()10760Sstevel@tonic-gate _init_ioctl()
10770Sstevel@tonic-gate {
10780Sstevel@tonic-gate 	mutex_init(&error_mutex, NULL, MUTEX_DRIVER, (void *)NULL);
10790Sstevel@tonic-gate 	return (1);
10800Sstevel@tonic-gate }
10810Sstevel@tonic-gate 
10820Sstevel@tonic-gate int
_fini_ioctl()10830Sstevel@tonic-gate _fini_ioctl()
10840Sstevel@tonic-gate {
10850Sstevel@tonic-gate 	mutex_destroy(&error_mutex);
10860Sstevel@tonic-gate 	return (1);
10870Sstevel@tonic-gate }
10880Sstevel@tonic-gate 
10890Sstevel@tonic-gate /*
10900Sstevel@tonic-gate  * END OF DEBUG ROUTINES
10910Sstevel@tonic-gate  */
10920Sstevel@tonic-gate #endif	/* DEBUG */
10930Sstevel@tonic-gate /*
10940Sstevel@tonic-gate  * BEGIN RELEASE DEBUG
10950Sstevel@tonic-gate  *	The following routines remain in the released product for testability
10960Sstevel@tonic-gate  */
10970Sstevel@tonic-gate 
10980Sstevel@tonic-gate /*
10990Sstevel@tonic-gate  * ufs error injection remains in the released product
11000Sstevel@tonic-gate  */
11010Sstevel@tonic-gate /*ARGSUSED1*/
11020Sstevel@tonic-gate static int
trans_ufserror(void * d,int mode,IOLOCK * lock)11030Sstevel@tonic-gate trans_ufserror(void *d, int mode, IOLOCK *lock)
11040Sstevel@tonic-gate {
11050Sstevel@tonic-gate 	mt_unit_t	*un;
11060Sstevel@tonic-gate 
11070Sstevel@tonic-gate 	md_i_get_t *migp = d;
11080Sstevel@tonic-gate 
11090Sstevel@tonic-gate 	mdclrerror(&migp->mde);
11100Sstevel@tonic-gate 
11110Sstevel@tonic-gate 	un = trans_getun(migp->id, &migp->mde,
11127563SPrasad.Singamsetty@Sun.COM 	    RD_LOCK, lock);
11130Sstevel@tonic-gate 	if (un == NULL || un->un_ut == NULL)
11140Sstevel@tonic-gate 		return (EINVAL);
11150Sstevel@tonic-gate 
11160Sstevel@tonic-gate 	return (0);
11170Sstevel@tonic-gate }
11180Sstevel@tonic-gate /*
11190Sstevel@tonic-gate  * shadow test remains in the released product
11200Sstevel@tonic-gate  */
11210Sstevel@tonic-gate static int
trans_set_shadow(void * d,int mode,IOLOCK * lock)11220Sstevel@tonic-gate trans_set_shadow(void *d, int mode, IOLOCK *lock)
11230Sstevel@tonic-gate {
11240Sstevel@tonic-gate 	dev32_t		device;			/* shadow device */
11250Sstevel@tonic-gate 	mt_unit_t 	*un;
11260Sstevel@tonic-gate 
11270Sstevel@tonic-gate 	md_i_get_t *migp = d;
11280Sstevel@tonic-gate 
11290Sstevel@tonic-gate 	mdclrerror(&migp->mde);
11300Sstevel@tonic-gate 
11310Sstevel@tonic-gate 	un = trans_getun(migp->id, &migp->mde,
11327563SPrasad.Singamsetty@Sun.COM 	    WR_LOCK, lock);
11330Sstevel@tonic-gate 	if (un == NULL)
11340Sstevel@tonic-gate 		return (EINVAL);
11350Sstevel@tonic-gate 
11360Sstevel@tonic-gate 	if ((un->un_debug & MT_SHADOW) == 0)
11370Sstevel@tonic-gate 		return (EINVAL);
11380Sstevel@tonic-gate 
11390Sstevel@tonic-gate 	/* Get shadow device.  User always passes down 32 bit devt */
11400Sstevel@tonic-gate 
11410Sstevel@tonic-gate 	if (ddi_copyin((caddr_t)(uintptr_t)migp->mdp,
11420Sstevel@tonic-gate 	    &device, sizeof (device), mode)) {
11430Sstevel@tonic-gate 		return (EFAULT);
11440Sstevel@tonic-gate 	}
11450Sstevel@tonic-gate 
11460Sstevel@tonic-gate 	/* Save shadow device designator. */
11470Sstevel@tonic-gate 	un->un_s_dev = md_expldev((md_dev64_t)device);
11480Sstevel@tonic-gate 	return (0);
11490Sstevel@tonic-gate }
11500Sstevel@tonic-gate 
11510Sstevel@tonic-gate /*
11520Sstevel@tonic-gate  * END RELEASE DEBUG
11530Sstevel@tonic-gate  */
11540Sstevel@tonic-gate 
11550Sstevel@tonic-gate static int
trans_get(void * d,int mode,IOLOCK * lock)11560Sstevel@tonic-gate trans_get(void *d, int mode, IOLOCK *lock)
11570Sstevel@tonic-gate {
11580Sstevel@tonic-gate 	mt_unit_t	*un;
11590Sstevel@tonic-gate 	ml_unit_t	*ul;
11600Sstevel@tonic-gate 
11610Sstevel@tonic-gate 	md_i_get_t *migp = d;
11620Sstevel@tonic-gate 
11630Sstevel@tonic-gate 	mdclrerror(&migp->mde);
11640Sstevel@tonic-gate 
11650Sstevel@tonic-gate 	un = trans_getun(migp->id, &migp->mde,
11667563SPrasad.Singamsetty@Sun.COM 	    RD_LOCK, lock);
11670Sstevel@tonic-gate 	if (un == NULL)
11680Sstevel@tonic-gate 		return (0);
11690Sstevel@tonic-gate 
11700Sstevel@tonic-gate 	if (migp->size == 0) {
11710Sstevel@tonic-gate 		migp->size = un->c.un_size;
11720Sstevel@tonic-gate 		return (0);
11730Sstevel@tonic-gate 	}
11740Sstevel@tonic-gate 
11750Sstevel@tonic-gate 	if (migp->size < un->c.un_size)
11760Sstevel@tonic-gate 		return (EFAULT);
11770Sstevel@tonic-gate 
11780Sstevel@tonic-gate log:
11790Sstevel@tonic-gate 	ul = un->un_l_unit;
11800Sstevel@tonic-gate 	if (ul == NULL)
11810Sstevel@tonic-gate 		goto master;
11820Sstevel@tonic-gate 
11830Sstevel@tonic-gate 	/*
11840Sstevel@tonic-gate 	 * refresh log fields in case log was metattach'ed
11850Sstevel@tonic-gate 	 */
11860Sstevel@tonic-gate 	un->un_l_head = (daddr32_t)btodb(ul->un_head_lof);
11870Sstevel@tonic-gate 	un->un_l_sblk = un->un_l_head;
11880Sstevel@tonic-gate 	un->un_l_pwsblk = ul->un_pwsblk;
11890Sstevel@tonic-gate 	un->un_l_maxtransfer = (uint_t)btodb(ul->un_maxtransfer);
11900Sstevel@tonic-gate 	un->un_l_nblks = ul->un_nblks;
11910Sstevel@tonic-gate 	un->un_l_tblks = ul->un_tblks;
11920Sstevel@tonic-gate 	un->un_l_tail = (daddr32_t)btodb(ul->un_tail_lof);
11930Sstevel@tonic-gate 	un->un_l_resv = ul->un_resv;
11940Sstevel@tonic-gate 	un->un_l_maxresv = ul->un_maxresv;
11950Sstevel@tonic-gate 	un->un_l_error = ul->un_error;
11960Sstevel@tonic-gate 	un->un_l_timestamp = ul->un_timestamp;
11970Sstevel@tonic-gate 
11980Sstevel@tonic-gate 	/*
11990Sstevel@tonic-gate 	 * check for log dev dynconcat; can only pick up extra space when the
12000Sstevel@tonic-gate 	 * tail physically follows the head in the circular log
12010Sstevel@tonic-gate 	 */
12020Sstevel@tonic-gate 	if (un->un_l_head <= un->un_l_tail)
12030Sstevel@tonic-gate 		if (ul->un_status & LDL_METADEVICE) {
12040Sstevel@tonic-gate 			struct mdc_unit	*c = MD_UNIT(md_getminor(ul->un_dev));
12050Sstevel@tonic-gate 
12060Sstevel@tonic-gate 			if (c->un_total_blocks > un->un_l_tblks) {
12070Sstevel@tonic-gate 				un->un_l_tblks = c->un_total_blocks;
12080Sstevel@tonic-gate 				un->un_l_nblks = un->un_l_tblks - un->un_l_sblk;
12090Sstevel@tonic-gate 				if (un->un_l_nblks > btodb(LDL_MAXLOGSIZE))
12100Sstevel@tonic-gate 					un->un_l_nblks = btodb(LDL_MAXLOGSIZE);
12110Sstevel@tonic-gate 				un->un_l_maxresv = (uint_t)(un->un_l_nblks *
12127563SPrasad.Singamsetty@Sun.COM 				    LDL_USABLE_BSIZE);
12130Sstevel@tonic-gate 			}
12140Sstevel@tonic-gate 	}
12150Sstevel@tonic-gate 
12160Sstevel@tonic-gate master:
12170Sstevel@tonic-gate 
12180Sstevel@tonic-gate 	if (ddi_copyout(un, (void *)(uintptr_t)migp->mdp, un->c.un_size, mode))
12190Sstevel@tonic-gate 		return (EFAULT);
12200Sstevel@tonic-gate 	return (0);
12210Sstevel@tonic-gate }
12220Sstevel@tonic-gate 
12230Sstevel@tonic-gate static int
trans_replace(replace_params_t * params)12240Sstevel@tonic-gate trans_replace(replace_params_t *params)
12250Sstevel@tonic-gate {
12260Sstevel@tonic-gate 	minor_t		mnum = params->mnum;
12270Sstevel@tonic-gate 	mt_unit_t	*un;
12280Sstevel@tonic-gate 	mdi_unit_t	*ui;
12297563SPrasad.Singamsetty@Sun.COM 	md_dev64_t	cmp_dev;
12307563SPrasad.Singamsetty@Sun.COM 	md_dev64_t	ldev;
12317563SPrasad.Singamsetty@Sun.COM 	md_dev64_t	mdev;
12320Sstevel@tonic-gate 
12330Sstevel@tonic-gate 	mdclrerror(&params->mde);
12340Sstevel@tonic-gate 
12350Sstevel@tonic-gate 	ui = MDI_UNIT(mnum);
12360Sstevel@tonic-gate 	un = md_unit_writerlock(ui);
12370Sstevel@tonic-gate 
12380Sstevel@tonic-gate 	if (MD_STATUS(un) & MD_UN_RESYNC_ACTIVE) {
12390Sstevel@tonic-gate 		return (mdmderror(&params->mde, MDE_RESYNC_ACTIVE, mnum));
12400Sstevel@tonic-gate 	}
12410Sstevel@tonic-gate 
12420Sstevel@tonic-gate 	cmp_dev = params->old_dev;
12430Sstevel@tonic-gate 	mdev = un->un_m_dev;
12440Sstevel@tonic-gate 	ldev = un->un_l_dev;
12450Sstevel@tonic-gate 	if (cmp_dev == mdev) {
12460Sstevel@tonic-gate 		un->un_m_key = params->new_key;
12470Sstevel@tonic-gate 		un->un_m_dev = params->new_dev;
12480Sstevel@tonic-gate 	} else if (cmp_dev == ldev) {
12490Sstevel@tonic-gate 		un->un_l_key = params->new_key;
12500Sstevel@tonic-gate 		un->un_l_dev = params->new_dev;
12510Sstevel@tonic-gate 	}
12520Sstevel@tonic-gate 
12530Sstevel@tonic-gate 	trans_commit(un, 1);
12540Sstevel@tonic-gate 	md_unit_writerexit(ui);
12550Sstevel@tonic-gate 	return (0);
12560Sstevel@tonic-gate }
12570Sstevel@tonic-gate 
12580Sstevel@tonic-gate /*ARGSUSED1*/
12590Sstevel@tonic-gate static int
trans_grow(void * d,int mode,IOLOCK * lock)12600Sstevel@tonic-gate trans_grow(void *d, int mode, IOLOCK  *lock)
12610Sstevel@tonic-gate {
12620Sstevel@tonic-gate 	mt_unit_t		*un;
12630Sstevel@tonic-gate 
12640Sstevel@tonic-gate 	md_grow_params_t *mgp = d;
12650Sstevel@tonic-gate 
12660Sstevel@tonic-gate 	mdclrerror(&mgp->mde);
12670Sstevel@tonic-gate 
12680Sstevel@tonic-gate 	un = trans_getun(mgp->mnum, &mgp->mde,
12697563SPrasad.Singamsetty@Sun.COM 	    RD_LOCK, lock);
12700Sstevel@tonic-gate 	if (un == NULL)
12710Sstevel@tonic-gate 		return (0);
12720Sstevel@tonic-gate 
12730Sstevel@tonic-gate 	/*
12740Sstevel@tonic-gate 	 * check for master dev dynconcat
12750Sstevel@tonic-gate 	 */
12760Sstevel@tonic-gate 	if (md_getmajor(un->un_m_dev) == md_major) {
12770Sstevel@tonic-gate 		struct mdc_unit	*c;
12780Sstevel@tonic-gate 
12790Sstevel@tonic-gate 		c = MD_UNIT(md_getminor(un->un_m_dev));
12800Sstevel@tonic-gate 		if (c->un_total_blocks > MD_MAX_BLKS_FOR_SMALL_DEVS) {
12810Sstevel@tonic-gate 			un->c.un_total_blocks = MD_MAX_BLKS_FOR_SMALL_DEVS;
12820Sstevel@tonic-gate 		} else {
12830Sstevel@tonic-gate 			un->c.un_total_blocks = c->un_total_blocks;
12840Sstevel@tonic-gate 		}
12857627SChris.Horne@Sun.COM 		md_nblocks_set(MD_SID(un), un->c.un_total_blocks);
12860Sstevel@tonic-gate 	}
12870Sstevel@tonic-gate 
12880Sstevel@tonic-gate 	return (0);
12890Sstevel@tonic-gate }
12900Sstevel@tonic-gate 
12910Sstevel@tonic-gate /*ARGSUSED1*/
12920Sstevel@tonic-gate static int
trans_detach_ioctl(void * d,int mode,IOLOCK * lock)12930Sstevel@tonic-gate trans_detach_ioctl(void *d, int mode, IOLOCK *lock)
12940Sstevel@tonic-gate {
12950Sstevel@tonic-gate 	mt_unit_t	*un;
12960Sstevel@tonic-gate 	int		error;
12970Sstevel@tonic-gate 
12980Sstevel@tonic-gate 	md_i_get_t *migp = d;
12990Sstevel@tonic-gate 
13000Sstevel@tonic-gate 	mdclrerror(&migp->mde);
13010Sstevel@tonic-gate 
13025331Samw 	/* acquire both md_unit_array_rw, and unit_reader lock */
13030Sstevel@tonic-gate 	un = trans_getun(migp->id, &migp->mde,
13047563SPrasad.Singamsetty@Sun.COM 	    READERS, lock);
13050Sstevel@tonic-gate 	if (un == NULL)
13060Sstevel@tonic-gate 		return (0);
13070Sstevel@tonic-gate 
13080Sstevel@tonic-gate 	/*
13090Sstevel@tonic-gate 	 * simply too much work to make debug modes w/out a log
13100Sstevel@tonic-gate 	 */
13110Sstevel@tonic-gate 	if (un->un_debug)
13120Sstevel@tonic-gate 		return (EACCES);
13130Sstevel@tonic-gate 
13140Sstevel@tonic-gate 	/*
13150Sstevel@tonic-gate 	 * detach the log
13160Sstevel@tonic-gate 	 */
13170Sstevel@tonic-gate 	error = trans_detach(un, migp->size);
13180Sstevel@tonic-gate 
13190Sstevel@tonic-gate 	return (error);
13200Sstevel@tonic-gate }
13210Sstevel@tonic-gate 
13220Sstevel@tonic-gate static int
trans_get_log(void * d,int mode,IOLOCK * lock)13230Sstevel@tonic-gate trans_get_log(void *d, int mode, IOLOCK	*lock)
13240Sstevel@tonic-gate {
13250Sstevel@tonic-gate 	mt_unit_t	*un;
13260Sstevel@tonic-gate 	ml_unit_t	*ul;
13270Sstevel@tonic-gate 
13280Sstevel@tonic-gate 	md_i_get_t *migp = d;
13290Sstevel@tonic-gate 
13300Sstevel@tonic-gate 	mdclrerror(&migp->mde);
13310Sstevel@tonic-gate 
13320Sstevel@tonic-gate 	un = trans_getun(migp->id, &migp->mde, RD_LOCK, lock);
13330Sstevel@tonic-gate 
13340Sstevel@tonic-gate 	if (un == NULL)
13350Sstevel@tonic-gate 		return (0);
13360Sstevel@tonic-gate 
13370Sstevel@tonic-gate 	ul = un->un_l_unit;
13380Sstevel@tonic-gate 
13390Sstevel@tonic-gate 	if (migp->size == 0) {
13400Sstevel@tonic-gate 		migp->size = ML_UNIT_ONDSZ;
13410Sstevel@tonic-gate 		return (0);
13420Sstevel@tonic-gate 	}
13430Sstevel@tonic-gate 
13440Sstevel@tonic-gate 	if (migp->size < ML_UNIT_ONDSZ)
13450Sstevel@tonic-gate 		return (EFAULT);
13460Sstevel@tonic-gate 
13470Sstevel@tonic-gate 	if (ddi_copyout(ul, (void *)(uintptr_t)migp->mdp, ML_UNIT_ONDSZ,
13480Sstevel@tonic-gate 	    mode))
13490Sstevel@tonic-gate 		return (EFAULT);
13500Sstevel@tonic-gate 	return (0);
13510Sstevel@tonic-gate }
13520Sstevel@tonic-gate 
13530Sstevel@tonic-gate static int
trans_getdevs(void * d,int mode,IOLOCK * lock)13540Sstevel@tonic-gate trans_getdevs(void *d, int mode, IOLOCK	*lock)
13550Sstevel@tonic-gate {
13560Sstevel@tonic-gate 	int			ndev;
13570Sstevel@tonic-gate 	mt_unit_t		*un;
13580Sstevel@tonic-gate 	md_dev64_t		*udevs;
13590Sstevel@tonic-gate 	md_dev64_t		unit_dev;
13600Sstevel@tonic-gate 
13610Sstevel@tonic-gate 	md_getdevs_params_t *mgdp = d;
13620Sstevel@tonic-gate 
13630Sstevel@tonic-gate 	mdclrerror(&mgdp->mde);
13640Sstevel@tonic-gate 
13650Sstevel@tonic-gate 	un = trans_getun(mgdp->mnum, &mgdp->mde, RD_LOCK, lock);
13660Sstevel@tonic-gate 	if (un == NULL)
13670Sstevel@tonic-gate 		return (0);
13680Sstevel@tonic-gate 
13690Sstevel@tonic-gate 	ndev = (un->un_flags & (TRANS_DETACHED | TRANS_ATTACHING)) ? 1 : 2;
13700Sstevel@tonic-gate 
13710Sstevel@tonic-gate 	if (mgdp->cnt == 0) {
13720Sstevel@tonic-gate 		mgdp->cnt = ndev;
13730Sstevel@tonic-gate 		return (0);
13740Sstevel@tonic-gate 	}
13750Sstevel@tonic-gate 
13760Sstevel@tonic-gate 	if (mgdp->cnt > 2)
13770Sstevel@tonic-gate 		mgdp->cnt = ndev;
13780Sstevel@tonic-gate 
13790Sstevel@tonic-gate 	udevs = (md_dev64_t *)(uintptr_t)mgdp->devs;
13800Sstevel@tonic-gate 	unit_dev = un->un_m_dev;
13810Sstevel@tonic-gate 
13820Sstevel@tonic-gate 	if (md_getmajor(unit_dev) != md_major) {
13830Sstevel@tonic-gate 		if ((unit_dev = md_xlate_mini_2_targ(unit_dev)) == NODEV64)
13840Sstevel@tonic-gate 			return (ENODEV);
13850Sstevel@tonic-gate 	}
13860Sstevel@tonic-gate 
13870Sstevel@tonic-gate 	if (mgdp->cnt >= 1)
13880Sstevel@tonic-gate 		if (ddi_copyout(&unit_dev, (caddr_t)&udevs[0],
13890Sstevel@tonic-gate 		    sizeof (*udevs), mode) != 0)
13900Sstevel@tonic-gate 			return (EFAULT);
13910Sstevel@tonic-gate 
13920Sstevel@tonic-gate 	unit_dev = un->un_l_dev;
13930Sstevel@tonic-gate 	if (md_getmajor(unit_dev) != md_major) {
13940Sstevel@tonic-gate 		if ((unit_dev = md_xlate_mini_2_targ(unit_dev)) == NODEV64)
13950Sstevel@tonic-gate 			return (ENODEV);
13960Sstevel@tonic-gate 	}
13970Sstevel@tonic-gate 
13980Sstevel@tonic-gate 	if (mgdp->cnt >= 2)
13990Sstevel@tonic-gate 		if (ddi_copyout(&unit_dev, (caddr_t)&udevs[1],
14000Sstevel@tonic-gate 		    sizeof (*udevs), mode) != 0)
14010Sstevel@tonic-gate 			return (EFAULT);
14020Sstevel@tonic-gate 
14030Sstevel@tonic-gate 	return (0);
14040Sstevel@tonic-gate }
14050Sstevel@tonic-gate 
14060Sstevel@tonic-gate static int
trans_reset_ioctl(md_i_reset_t * mirp,IOLOCK * lock)14070Sstevel@tonic-gate trans_reset_ioctl(md_i_reset_t *mirp, IOLOCK *lock)
14080Sstevel@tonic-gate {
14090Sstevel@tonic-gate 	minor_t		mnum = mirp->mnum;
14100Sstevel@tonic-gate 	mt_unit_t	*un;
14110Sstevel@tonic-gate 	int		error;
14120Sstevel@tonic-gate 
14130Sstevel@tonic-gate 	mdclrerror(&mirp->mde);
14140Sstevel@tonic-gate 
14150Sstevel@tonic-gate 	un = trans_getun(mnum, &mirp->mde, NO_LOCK, lock);
14160Sstevel@tonic-gate 	if (un == NULL)
14170Sstevel@tonic-gate 		return (0);
14180Sstevel@tonic-gate 
14190Sstevel@tonic-gate 
14200Sstevel@tonic-gate 	/* This prevents new opens */
14210Sstevel@tonic-gate 	rw_enter(&md_unit_array_rw.lock, RW_WRITER);
14220Sstevel@tonic-gate 
14230Sstevel@tonic-gate 	if (MD_HAS_PARENT(MD_PARENT(un))) {
14240Sstevel@tonic-gate 		rw_exit(&md_unit_array_rw.lock);
14250Sstevel@tonic-gate 		return (mdmderror(&mirp->mde, MDE_IN_USE, mnum));
14260Sstevel@tonic-gate 	}
14270Sstevel@tonic-gate 
14280Sstevel@tonic-gate 	if (md_unit_isopen(MDI_UNIT(mnum))) {
14290Sstevel@tonic-gate 		rw_exit(&md_unit_array_rw.lock);
14300Sstevel@tonic-gate 		return (mdmderror(&mirp->mde, MDE_IS_OPEN, mnum));
14310Sstevel@tonic-gate 	}
14320Sstevel@tonic-gate 	/*
14330Sstevel@tonic-gate 	 * detach the log
14340Sstevel@tonic-gate 	 */
14350Sstevel@tonic-gate 	error = trans_detach(un, mirp->force);
14360Sstevel@tonic-gate 
14370Sstevel@tonic-gate 	/*
14380Sstevel@tonic-gate 	 * reset (aka remove; aka delete) the trans device
14390Sstevel@tonic-gate 	 */
14400Sstevel@tonic-gate 	if (error == 0)
14410Sstevel@tonic-gate 		error = trans_reset(un, mnum, 1, mirp->force);
14420Sstevel@tonic-gate 
14430Sstevel@tonic-gate 	rw_exit(&md_unit_array_rw.lock);
14440Sstevel@tonic-gate 	return (error);
14450Sstevel@tonic-gate }
14460Sstevel@tonic-gate 
14470Sstevel@tonic-gate static int
trans_get_geom(mt_unit_t * un,struct dk_geom * geomp)14480Sstevel@tonic-gate trans_get_geom(mt_unit_t *un, struct dk_geom *geomp)
14490Sstevel@tonic-gate {
14500Sstevel@tonic-gate 	md_get_geom((md_unit_t *)un, geomp);
14510Sstevel@tonic-gate 
14520Sstevel@tonic-gate 	return (0);
14530Sstevel@tonic-gate }
14540Sstevel@tonic-gate 
14550Sstevel@tonic-gate static int
trans_get_vtoc(mt_unit_t * un,struct vtoc * vtocp)14560Sstevel@tonic-gate trans_get_vtoc(mt_unit_t *un, struct vtoc *vtocp)
14570Sstevel@tonic-gate {
14580Sstevel@tonic-gate 	md_get_vtoc((md_unit_t *)un, vtocp);
14590Sstevel@tonic-gate 
14600Sstevel@tonic-gate 	return (0);
14610Sstevel@tonic-gate }
14620Sstevel@tonic-gate 
14630Sstevel@tonic-gate static int
trans_get_extvtoc(mt_unit_t * un,struct extvtoc * vtocp)14647563SPrasad.Singamsetty@Sun.COM trans_get_extvtoc(mt_unit_t *un, struct extvtoc *vtocp)
14657563SPrasad.Singamsetty@Sun.COM {
14667563SPrasad.Singamsetty@Sun.COM 	md_get_extvtoc((md_unit_t *)un, vtocp);
14677563SPrasad.Singamsetty@Sun.COM 
14687563SPrasad.Singamsetty@Sun.COM 	return (0);
14697563SPrasad.Singamsetty@Sun.COM }
14707563SPrasad.Singamsetty@Sun.COM 
14717563SPrasad.Singamsetty@Sun.COM static int
trans_islog(mt_unit_t * un)14720Sstevel@tonic-gate trans_islog(mt_unit_t *un)
14730Sstevel@tonic-gate {
14740Sstevel@tonic-gate 	if (un->un_l_unit == NULL)
14750Sstevel@tonic-gate 		return (ENXIO);
14760Sstevel@tonic-gate 	return (0);
14770Sstevel@tonic-gate }
14780Sstevel@tonic-gate 
14790Sstevel@tonic-gate static int
trans_set_vtoc(mt_unit_t * un,struct vtoc * vtocp)14800Sstevel@tonic-gate trans_set_vtoc(
14810Sstevel@tonic-gate 	mt_unit_t	*un,
14820Sstevel@tonic-gate 	struct vtoc	*vtocp
14830Sstevel@tonic-gate )
14840Sstevel@tonic-gate {
14850Sstevel@tonic-gate 	return (md_set_vtoc((md_unit_t *)un, vtocp));
14860Sstevel@tonic-gate }
14870Sstevel@tonic-gate 
14880Sstevel@tonic-gate static int
trans_set_extvtoc(mt_unit_t * un,struct extvtoc * vtocp)14897563SPrasad.Singamsetty@Sun.COM trans_set_extvtoc(mt_unit_t *un, struct extvtoc *vtocp)
14907563SPrasad.Singamsetty@Sun.COM {
14917563SPrasad.Singamsetty@Sun.COM 	return (md_set_extvtoc((md_unit_t *)un, vtocp));
14927563SPrasad.Singamsetty@Sun.COM }
14937563SPrasad.Singamsetty@Sun.COM 
14947563SPrasad.Singamsetty@Sun.COM static int
trans_get_cgapart(mt_unit_t * un,struct dk_map * dkmapp)14950Sstevel@tonic-gate trans_get_cgapart(
14960Sstevel@tonic-gate 	mt_unit_t	*un,
14970Sstevel@tonic-gate 	struct dk_map	*dkmapp
14980Sstevel@tonic-gate )
14990Sstevel@tonic-gate {
15000Sstevel@tonic-gate 	md_get_cgapart((md_unit_t *)un, dkmapp);
15010Sstevel@tonic-gate 	return (0);
15020Sstevel@tonic-gate }
15030Sstevel@tonic-gate 
15040Sstevel@tonic-gate static int
trans_admin_ioctl(int cmd,caddr_t data,int mode,IOLOCK * lockp)15050Sstevel@tonic-gate trans_admin_ioctl(
15060Sstevel@tonic-gate 	int	cmd,
15070Sstevel@tonic-gate 	caddr_t	data,
15080Sstevel@tonic-gate 	int	mode,
15090Sstevel@tonic-gate 	IOLOCK	*lockp
15100Sstevel@tonic-gate )
15110Sstevel@tonic-gate {
15120Sstevel@tonic-gate 	size_t	sz = 0;
15130Sstevel@tonic-gate 	void	*d = NULL;
15140Sstevel@tonic-gate 	int	err = 0;
15150Sstevel@tonic-gate 
15160Sstevel@tonic-gate 	/* We can only handle 32-bit clients for internal commands */
15170Sstevel@tonic-gate 	if ((mode & DATAMODEL_MASK) != DATAMODEL_ILP32) {
15180Sstevel@tonic-gate 		return (EINVAL);
15190Sstevel@tonic-gate 	}
15200Sstevel@tonic-gate 
15210Sstevel@tonic-gate 	switch (cmd) {
15220Sstevel@tonic-gate 
15230Sstevel@tonic-gate 	case MD_IOCGET:
15240Sstevel@tonic-gate 	{
15250Sstevel@tonic-gate 		if (! (mode & FREAD))
15260Sstevel@tonic-gate 			return (EACCES);
15270Sstevel@tonic-gate 
15280Sstevel@tonic-gate 		sz = sizeof (md_i_get_t);
15290Sstevel@tonic-gate 
15300Sstevel@tonic-gate 		if ((d = md_trans_zalloc(sz)) == NULL)
15310Sstevel@tonic-gate 			return (ENOMEM);
15320Sstevel@tonic-gate 
15330Sstevel@tonic-gate 		if (ddi_copyin(data, d, sz, mode)) {
15340Sstevel@tonic-gate 			err = EFAULT;
15350Sstevel@tonic-gate 			break;
15360Sstevel@tonic-gate 		}
15370Sstevel@tonic-gate 
15380Sstevel@tonic-gate 		err = trans_get(d, mode, lockp);
15390Sstevel@tonic-gate 		break;
15400Sstevel@tonic-gate 	}
15410Sstevel@tonic-gate 
15420Sstevel@tonic-gate 	case MD_IOCGET_LOG:
15430Sstevel@tonic-gate 	{
15440Sstevel@tonic-gate 		if (! (mode & FREAD))
15450Sstevel@tonic-gate 			return (EACCES);
15460Sstevel@tonic-gate 
15470Sstevel@tonic-gate 		sz = sizeof (md_i_get_t);
15480Sstevel@tonic-gate 
15490Sstevel@tonic-gate 		if ((d = md_trans_zalloc(sz)) == NULL)
15500Sstevel@tonic-gate 			return (ENOMEM);
15510Sstevel@tonic-gate 
15520Sstevel@tonic-gate 		if (ddi_copyin(data, d, sz, mode)) {
15530Sstevel@tonic-gate 			err = EFAULT;
15540Sstevel@tonic-gate 			break;
15550Sstevel@tonic-gate 		}
15560Sstevel@tonic-gate 
15570Sstevel@tonic-gate 		err = trans_get_log(d, mode, lockp);
15580Sstevel@tonic-gate 		break;
15590Sstevel@tonic-gate 	}
15600Sstevel@tonic-gate 
15610Sstevel@tonic-gate 	case MD_IOCRESET:
15620Sstevel@tonic-gate 	{
15630Sstevel@tonic-gate 		md_i_reset_t	*p;
15640Sstevel@tonic-gate 
15650Sstevel@tonic-gate 		if (! (mode & FWRITE))
15660Sstevel@tonic-gate 			return (EACCES);
15670Sstevel@tonic-gate 
15680Sstevel@tonic-gate 		if ((d = p = md_trans_zalloc((sz = sizeof (*p)))) == NULL)
15690Sstevel@tonic-gate 			return (ENOMEM);
15700Sstevel@tonic-gate 
15710Sstevel@tonic-gate 		if (ddi_copyin(data, d, sz, mode)) {
15720Sstevel@tonic-gate 			err = EFAULT;
15730Sstevel@tonic-gate 			break;
15740Sstevel@tonic-gate 		}
15750Sstevel@tonic-gate 
15760Sstevel@tonic-gate 		err = trans_reset_ioctl(p, lockp);
15770Sstevel@tonic-gate 		break;
15780Sstevel@tonic-gate 	}
15790Sstevel@tonic-gate 
15800Sstevel@tonic-gate 	case MD_IOCGROW:
15810Sstevel@tonic-gate 	{
15820Sstevel@tonic-gate 		if (! (mode & FWRITE))
15830Sstevel@tonic-gate 			return (EACCES);
15840Sstevel@tonic-gate 
15850Sstevel@tonic-gate 		sz = sizeof (md_grow_params_t);
15860Sstevel@tonic-gate 
15870Sstevel@tonic-gate 		if ((d = md_trans_zalloc(sz)) == NULL)
15880Sstevel@tonic-gate 			return (ENOMEM);
15890Sstevel@tonic-gate 
15900Sstevel@tonic-gate 		if (ddi_copyin(data, d, sz, mode)) {
15910Sstevel@tonic-gate 			err = EFAULT;
15920Sstevel@tonic-gate 			break;
15930Sstevel@tonic-gate 		}
15940Sstevel@tonic-gate 
15950Sstevel@tonic-gate 		err = trans_grow(d, mode, lockp);
15960Sstevel@tonic-gate 		break;
15970Sstevel@tonic-gate 	}
15980Sstevel@tonic-gate 
15990Sstevel@tonic-gate 	case MD_IOC_TRANS_DETACH:
16000Sstevel@tonic-gate 	{
16010Sstevel@tonic-gate 		if (! (mode & FWRITE))
16020Sstevel@tonic-gate 			return (EACCES);
16030Sstevel@tonic-gate 
16040Sstevel@tonic-gate 		sz = sizeof (md_i_get_t);
16050Sstevel@tonic-gate 
16060Sstevel@tonic-gate 		if ((d = md_trans_zalloc(sz)) == NULL)
16070Sstevel@tonic-gate 			return (ENOMEM);
16080Sstevel@tonic-gate 
16090Sstevel@tonic-gate 		if (ddi_copyin(data, d, sz, mode)) {
16100Sstevel@tonic-gate 			err = EFAULT;
16110Sstevel@tonic-gate 			break;
16120Sstevel@tonic-gate 		}
16130Sstevel@tonic-gate 
16140Sstevel@tonic-gate 		err = trans_detach_ioctl(d, mode, lockp);
16150Sstevel@tonic-gate 		break;
16160Sstevel@tonic-gate 	}
16170Sstevel@tonic-gate 
16180Sstevel@tonic-gate 	case MD_IOCREPLACE:
16190Sstevel@tonic-gate 	{
16200Sstevel@tonic-gate 		replace_params_t	*p;
16210Sstevel@tonic-gate 
16220Sstevel@tonic-gate 		if (! (mode & FWRITE))
16230Sstevel@tonic-gate 			return (EACCES);
16240Sstevel@tonic-gate 
16250Sstevel@tonic-gate 		if ((d = p = kmem_alloc((sz = sizeof (*p)), KM_SLEEP)) == NULL)
16260Sstevel@tonic-gate 			return (ENOMEM);
16270Sstevel@tonic-gate 
16280Sstevel@tonic-gate 		if (ddi_copyin(data, d, sz, mode)) {
16290Sstevel@tonic-gate 			err = EFAULT;
16300Sstevel@tonic-gate 			break;
16310Sstevel@tonic-gate 		}
16320Sstevel@tonic-gate 
16330Sstevel@tonic-gate 		err = trans_replace(p);
16340Sstevel@tonic-gate 		break;
16350Sstevel@tonic-gate 	}
16360Sstevel@tonic-gate 
16370Sstevel@tonic-gate 
16380Sstevel@tonic-gate 	case MD_IOCGET_DEVS:
16390Sstevel@tonic-gate 	{
16400Sstevel@tonic-gate 		if (! (mode & FREAD))
16410Sstevel@tonic-gate 			return (EACCES);
16420Sstevel@tonic-gate 
16430Sstevel@tonic-gate 		sz = sizeof (md_getdevs_params_t);
16440Sstevel@tonic-gate 
16450Sstevel@tonic-gate 		if ((d = md_trans_zalloc(sz)) == NULL)
16460Sstevel@tonic-gate 			return (ENOMEM);
16470Sstevel@tonic-gate 
16480Sstevel@tonic-gate 		if (ddi_copyin(data, d, sz, mode)) {
16490Sstevel@tonic-gate 			err = EFAULT;
16500Sstevel@tonic-gate 			break;
16510Sstevel@tonic-gate 		}
16520Sstevel@tonic-gate 
16530Sstevel@tonic-gate 		err = trans_getdevs(d, mode, lockp);
16540Sstevel@tonic-gate 		break;
16550Sstevel@tonic-gate 	}
16560Sstevel@tonic-gate 
16570Sstevel@tonic-gate /*
16580Sstevel@tonic-gate  * debug ioctls
16590Sstevel@tonic-gate  */
16600Sstevel@tonic-gate #ifdef	DEBUG
16610Sstevel@tonic-gate 
16620Sstevel@tonic-gate 
16630Sstevel@tonic-gate 	case MD_IOCGET_TRANSSTATS:
16640Sstevel@tonic-gate 	{
16650Sstevel@tonic-gate 		if (! (mode & FREAD))
16660Sstevel@tonic-gate 			return (EACCES);
16670Sstevel@tonic-gate 
16680Sstevel@tonic-gate 		sz = sizeof (md_i_get_t);
16690Sstevel@tonic-gate 
16700Sstevel@tonic-gate 		if ((d = md_trans_zalloc(sz)) == NULL)
16710Sstevel@tonic-gate 			return (ENOMEM);
16720Sstevel@tonic-gate 
16730Sstevel@tonic-gate 		if (ddi_copyin(data, d, sz, mode)) {
16740Sstevel@tonic-gate 			err = EFAULT;
16750Sstevel@tonic-gate 			break;
16760Sstevel@tonic-gate 		}
16770Sstevel@tonic-gate 
16780Sstevel@tonic-gate 		err = trans_get_transstats(d, mode);
16790Sstevel@tonic-gate 		break;
16800Sstevel@tonic-gate 	}
16810Sstevel@tonic-gate 
16820Sstevel@tonic-gate 	case MD_IOC_DEBUG:
16830Sstevel@tonic-gate 	{
16840Sstevel@tonic-gate 		md_i_get_t *mdigp;
16850Sstevel@tonic-gate 
16860Sstevel@tonic-gate 		if (! (mode & FWRITE))
16870Sstevel@tonic-gate 			return (EACCES);
16880Sstevel@tonic-gate 
16890Sstevel@tonic-gate 		sz = sizeof (md_i_get_t);
16900Sstevel@tonic-gate 
16910Sstevel@tonic-gate 		if ((d = md_trans_zalloc(sz)) == NULL)
16920Sstevel@tonic-gate 			return (ENOMEM);
16930Sstevel@tonic-gate 
16940Sstevel@tonic-gate 		if (ddi_copyin(data, d, sz, mode)) {
16950Sstevel@tonic-gate 			err = EFAULT;
16960Sstevel@tonic-gate 			break;
16970Sstevel@tonic-gate 		}
16980Sstevel@tonic-gate 
16990Sstevel@tonic-gate 		mdigp = d;
17000Sstevel@tonic-gate 
17010Sstevel@tonic-gate 		mdclrerror(&mdigp->mde);
17020Sstevel@tonic-gate 		mt_debug = mdigp->size;
17030Sstevel@tonic-gate 		break;
17040Sstevel@tonic-gate 	}
17050Sstevel@tonic-gate 
17060Sstevel@tonic-gate 	case MD_IOC_TSD:
17070Sstevel@tonic-gate 	{
17080Sstevel@tonic-gate 		if (! (mode & FWRITE))
17090Sstevel@tonic-gate 			return (EACCES);
17100Sstevel@tonic-gate 
17110Sstevel@tonic-gate 
17120Sstevel@tonic-gate 		sz = sizeof (md_i_get_t);
17130Sstevel@tonic-gate 
17140Sstevel@tonic-gate 		if ((d = md_trans_zalloc(sz)) == NULL)
17150Sstevel@tonic-gate 			return (ENOMEM);
17160Sstevel@tonic-gate 
17170Sstevel@tonic-gate 		if (ddi_copyin(data, d, sz, mode)) {
17180Sstevel@tonic-gate 			err = EFAULT;
17190Sstevel@tonic-gate 			break;
17200Sstevel@tonic-gate 		}
17210Sstevel@tonic-gate 
17220Sstevel@tonic-gate 		err = trans_test_tsd(d, mode);
17230Sstevel@tonic-gate 		break;
17240Sstevel@tonic-gate 	}
17250Sstevel@tonic-gate 
17260Sstevel@tonic-gate 	case MD_IOC_TRYGETBLK:
17270Sstevel@tonic-gate 	{
17280Sstevel@tonic-gate 		if (! (mode & FWRITE))
17290Sstevel@tonic-gate 			return (EACCES);
17300Sstevel@tonic-gate 
17310Sstevel@tonic-gate 
17320Sstevel@tonic-gate 		sz = sizeof (md_i_get_t);
17330Sstevel@tonic-gate 
17340Sstevel@tonic-gate 		if ((d = md_trans_zalloc(sz)) == NULL)
17350Sstevel@tonic-gate 			return (ENOMEM);
17360Sstevel@tonic-gate 
17370Sstevel@tonic-gate 		if (ddi_copyin(data, d, sz, mode)) {
17380Sstevel@tonic-gate 			err = EFAULT;
17390Sstevel@tonic-gate 			break;
17400Sstevel@tonic-gate 		}
17410Sstevel@tonic-gate 
17420Sstevel@tonic-gate 		err = trans_test_trygetblk(d, mode, lockp);
17430Sstevel@tonic-gate 		break;
17440Sstevel@tonic-gate 	}
17450Sstevel@tonic-gate 
17460Sstevel@tonic-gate 	case MD_IOC_TRYPAGE:
17470Sstevel@tonic-gate 	{
17480Sstevel@tonic-gate 		if (! (mode & FWRITE))
17490Sstevel@tonic-gate 			return (EACCES);
17500Sstevel@tonic-gate 
17510Sstevel@tonic-gate 
17520Sstevel@tonic-gate 		sz = sizeof (md_i_get_t);
17530Sstevel@tonic-gate 
17540Sstevel@tonic-gate 		if ((d = md_trans_zalloc(sz)) == NULL)
17550Sstevel@tonic-gate 			return (ENOMEM);
17560Sstevel@tonic-gate 
17570Sstevel@tonic-gate 		if (ddi_copyin(data, d, sz, mode)) {
17580Sstevel@tonic-gate 			err = EFAULT;
17590Sstevel@tonic-gate 			break;
17600Sstevel@tonic-gate 		}
17610Sstevel@tonic-gate 
17620Sstevel@tonic-gate 		err = trans_test_trypage(d, mode, lockp);
17630Sstevel@tonic-gate 		break;
17640Sstevel@tonic-gate 	}
17650Sstevel@tonic-gate 
17660Sstevel@tonic-gate 
17670Sstevel@tonic-gate 	case MD_IOC_INJECTERRORS:
17680Sstevel@tonic-gate 	{
17690Sstevel@tonic-gate 		if (! (mode & FWRITE))
17700Sstevel@tonic-gate 			return (EACCES);
17710Sstevel@tonic-gate 
17720Sstevel@tonic-gate 
17730Sstevel@tonic-gate 		sz = sizeof (md_i_get_t);
17740Sstevel@tonic-gate 
17750Sstevel@tonic-gate 		if ((d = md_trans_zalloc(sz)) == NULL)
17760Sstevel@tonic-gate 			return (ENOMEM);
17770Sstevel@tonic-gate 
17780Sstevel@tonic-gate 		if (ddi_copyin(data, d, sz, mode)) {
17790Sstevel@tonic-gate 			err = EFAULT;
17800Sstevel@tonic-gate 			break;
17810Sstevel@tonic-gate 		}
17820Sstevel@tonic-gate 
17830Sstevel@tonic-gate 		err = trans_inject_errors(d, mode, lockp);
17840Sstevel@tonic-gate 		break;
17850Sstevel@tonic-gate 	}
17860Sstevel@tonic-gate 
17870Sstevel@tonic-gate 	case MD_IOC_STOPERRORS:
17880Sstevel@tonic-gate 	{
17890Sstevel@tonic-gate 		if (! (mode & FWRITE))
17900Sstevel@tonic-gate 			return (EACCES);
17910Sstevel@tonic-gate 
17920Sstevel@tonic-gate 
17930Sstevel@tonic-gate 		sz = sizeof (md_i_get_t);
17940Sstevel@tonic-gate 
17950Sstevel@tonic-gate 		if ((d = md_trans_zalloc(sz)) == NULL)
17960Sstevel@tonic-gate 			return (ENOMEM);
17970Sstevel@tonic-gate 
17980Sstevel@tonic-gate 		if (ddi_copyin(data, d, sz, mode)) {
17990Sstevel@tonic-gate 			err = EFAULT;
18000Sstevel@tonic-gate 			break;
18010Sstevel@tonic-gate 		}
18020Sstevel@tonic-gate 
18030Sstevel@tonic-gate 		err = trans_stop_errors(d, mode, lockp);
18040Sstevel@tonic-gate 		break;
18050Sstevel@tonic-gate 	}
18060Sstevel@tonic-gate 
18070Sstevel@tonic-gate 	case MD_IOC_ISDEBUG:
18080Sstevel@tonic-gate 		break;
18090Sstevel@tonic-gate 
18100Sstevel@tonic-gate #else	/* ! DEBUG */
18110Sstevel@tonic-gate 
18120Sstevel@tonic-gate 	case MD_IOC_ISDEBUG:
18130Sstevel@tonic-gate 	case MD_IOCGET_TRANSSTATS:
18140Sstevel@tonic-gate 	case MD_IOC_STOPERRORS:
18150Sstevel@tonic-gate 	case MD_IOC_TSD:
18160Sstevel@tonic-gate 	case MD_IOC_TRYGETBLK:
18170Sstevel@tonic-gate 	case MD_IOC_TRYPAGE:
18180Sstevel@tonic-gate 		break;
18190Sstevel@tonic-gate 
18200Sstevel@tonic-gate 	/*
18210Sstevel@tonic-gate 	 * error injection behaves like MD_IOC_UFSERROR in released product
18220Sstevel@tonic-gate 	 */
18230Sstevel@tonic-gate 	case MD_IOC_INJECTERRORS:
18240Sstevel@tonic-gate 	{
18250Sstevel@tonic-gate 		if (! (mode & FWRITE))
18260Sstevel@tonic-gate 			return (EACCES);
18270Sstevel@tonic-gate 
18280Sstevel@tonic-gate 
18290Sstevel@tonic-gate 		sz = sizeof (md_i_get_t);
18300Sstevel@tonic-gate 
18310Sstevel@tonic-gate 		if ((d = md_trans_zalloc(sz)) == NULL)
18320Sstevel@tonic-gate 			return (ENOMEM);
18330Sstevel@tonic-gate 
18340Sstevel@tonic-gate 		if (ddi_copyin(data, d, sz, mode)) {
18350Sstevel@tonic-gate 			err = EFAULT;
18360Sstevel@tonic-gate 			break;
18370Sstevel@tonic-gate 		}
18380Sstevel@tonic-gate 
18390Sstevel@tonic-gate 		err = trans_ufserror(d, mode, lockp);
18400Sstevel@tonic-gate 		break;
18410Sstevel@tonic-gate 	}
18420Sstevel@tonic-gate 
18430Sstevel@tonic-gate 	/*
18440Sstevel@tonic-gate 	 * only the shadow test is allowed in the released product
18450Sstevel@tonic-gate 	 */
18460Sstevel@tonic-gate 	case MD_IOC_DEBUG:
18470Sstevel@tonic-gate 	{
18480Sstevel@tonic-gate 		md_i_get_t *mdigp;
18490Sstevel@tonic-gate 
18500Sstevel@tonic-gate 		if (! (mode & FWRITE))
18510Sstevel@tonic-gate 			return (EACCES);
18520Sstevel@tonic-gate 
18530Sstevel@tonic-gate 		sz = sizeof (md_i_get_t);
18540Sstevel@tonic-gate 
18550Sstevel@tonic-gate 		if ((d = md_trans_zalloc(sz)) == NULL)
18560Sstevel@tonic-gate 			return (ENOMEM);
18570Sstevel@tonic-gate 
18580Sstevel@tonic-gate 		if (ddi_copyin(data, d, sz, mode)) {
18590Sstevel@tonic-gate 			err = EFAULT;
18600Sstevel@tonic-gate 			break;
18610Sstevel@tonic-gate 		}
18620Sstevel@tonic-gate 
18630Sstevel@tonic-gate 		mdigp = d;
18640Sstevel@tonic-gate 
18650Sstevel@tonic-gate 		mdclrerror(&mdigp->mde);
18660Sstevel@tonic-gate 		mt_debug = mdigp->size & MT_SHADOW;
18670Sstevel@tonic-gate 		break;
18680Sstevel@tonic-gate 	}
18690Sstevel@tonic-gate 
18700Sstevel@tonic-gate #endif	/* ! DEBUG */
18710Sstevel@tonic-gate 
18720Sstevel@tonic-gate /*
18730Sstevel@tonic-gate  * BEGIN RELEASE DEBUG
18740Sstevel@tonic-gate  *	The following routines remain in the released product for testability
18750Sstevel@tonic-gate  */
18760Sstevel@tonic-gate 
18770Sstevel@tonic-gate 	case MD_IOC_UFSERROR:
18780Sstevel@tonic-gate 	{
18790Sstevel@tonic-gate 		if (! (mode & FWRITE))
18800Sstevel@tonic-gate 			return (EACCES);
18810Sstevel@tonic-gate 
18820Sstevel@tonic-gate 		sz = sizeof (md_i_get_t);
18830Sstevel@tonic-gate 
18840Sstevel@tonic-gate 		if ((d = md_trans_zalloc(sz)) == NULL)
18850Sstevel@tonic-gate 			return (ENOMEM);
18860Sstevel@tonic-gate 
18870Sstevel@tonic-gate 		if (ddi_copyin(data, d, sz, mode)) {
18880Sstevel@tonic-gate 			err = EFAULT;
18890Sstevel@tonic-gate 			break;
18900Sstevel@tonic-gate 		}
18910Sstevel@tonic-gate 
18920Sstevel@tonic-gate 		err = trans_ufserror(d, mode, lockp);
18930Sstevel@tonic-gate 		break;
18940Sstevel@tonic-gate 	}
18950Sstevel@tonic-gate 
18960Sstevel@tonic-gate 	case MD_IOC_SETSHADOW:
18970Sstevel@tonic-gate 	{
18980Sstevel@tonic-gate 		if (! (mode & FWRITE))
18990Sstevel@tonic-gate 			return (EACCES);
19000Sstevel@tonic-gate 
19010Sstevel@tonic-gate 		sz = sizeof (md_i_get_t);
19020Sstevel@tonic-gate 
19030Sstevel@tonic-gate 		if ((d = md_trans_zalloc(sz)) == NULL)
19040Sstevel@tonic-gate 			return (ENOMEM);
19050Sstevel@tonic-gate 
19060Sstevel@tonic-gate 		if (ddi_copyin(data, d, sz, mode)) {
19070Sstevel@tonic-gate 			err = EFAULT;
19080Sstevel@tonic-gate 			break;
19090Sstevel@tonic-gate 		}
19100Sstevel@tonic-gate 
19110Sstevel@tonic-gate 		err = trans_set_shadow(d, mode, lockp);
19120Sstevel@tonic-gate 		break;
19130Sstevel@tonic-gate 	}
19140Sstevel@tonic-gate 
19150Sstevel@tonic-gate /*
19160Sstevel@tonic-gate  * END RELEASE DEBUG
19170Sstevel@tonic-gate  */
19180Sstevel@tonic-gate 
19190Sstevel@tonic-gate 
19200Sstevel@tonic-gate 	default:
19210Sstevel@tonic-gate 		return (ENOTTY);
19220Sstevel@tonic-gate 	}
19230Sstevel@tonic-gate 
19240Sstevel@tonic-gate 	/*
19250Sstevel@tonic-gate 	 * copyout and free any args
19260Sstevel@tonic-gate 	 */
19270Sstevel@tonic-gate 	if (sz != 0) {
19280Sstevel@tonic-gate 		if (err == 0) {
19290Sstevel@tonic-gate 			if (ddi_copyout(d, data, sz, mode) != 0) {
19300Sstevel@tonic-gate 				err = EFAULT;
19310Sstevel@tonic-gate 			}
19320Sstevel@tonic-gate 		}
19330Sstevel@tonic-gate 		md_trans_free(d, sz);
19340Sstevel@tonic-gate 	}
19350Sstevel@tonic-gate 	return (err);
19360Sstevel@tonic-gate }
19370Sstevel@tonic-gate 
19380Sstevel@tonic-gate int
md_trans_ioctl(dev_t dev,int cmd,caddr_t data,int mode,IOLOCK * lockp)19390Sstevel@tonic-gate md_trans_ioctl(
19400Sstevel@tonic-gate 	dev_t		dev,
19410Sstevel@tonic-gate 	int		cmd,
19420Sstevel@tonic-gate 	caddr_t		data,
19430Sstevel@tonic-gate 	int		mode,
19440Sstevel@tonic-gate 	IOLOCK		*lockp
19450Sstevel@tonic-gate )
19460Sstevel@tonic-gate {
19470Sstevel@tonic-gate 	minor_t		mnum = getminor(dev);
19480Sstevel@tonic-gate 	mt_unit_t	*un;
19490Sstevel@tonic-gate 	md_error_t	mde = mdnullerror;
19500Sstevel@tonic-gate 	int		err = 0;
19510Sstevel@tonic-gate 
19520Sstevel@tonic-gate 	/* handle admin ioctls */
19530Sstevel@tonic-gate 	if (mnum == MD_ADM_MINOR)
19540Sstevel@tonic-gate 		return (trans_admin_ioctl(cmd, data, mode, lockp));
19550Sstevel@tonic-gate 
19560Sstevel@tonic-gate 	/* check unit */
19570Sstevel@tonic-gate 	if ((MD_MIN2SET(mnum) >= md_nsets) ||
19580Sstevel@tonic-gate 	    (MD_MIN2UNIT(mnum) >= md_nunits) ||
19590Sstevel@tonic-gate 	    ((un = trans_getun(mnum, &mde, RD_LOCK, lockp)) == NULL))
19600Sstevel@tonic-gate 		return (ENXIO);
19610Sstevel@tonic-gate 
19620Sstevel@tonic-gate 	/* dispatch ioctl */
19630Sstevel@tonic-gate 	switch (cmd) {
19640Sstevel@tonic-gate 
19650Sstevel@tonic-gate 	case DKIOCINFO:
19660Sstevel@tonic-gate 	{
19670Sstevel@tonic-gate 		struct dk_cinfo	*p;
19680Sstevel@tonic-gate 
19690Sstevel@tonic-gate 		if (! (mode & FREAD))
19700Sstevel@tonic-gate 			return (EACCES);
19710Sstevel@tonic-gate 
19720Sstevel@tonic-gate 		if ((p = md_trans_zalloc(sizeof (*p))) == NULL)
19730Sstevel@tonic-gate 			return (ENOMEM);
19740Sstevel@tonic-gate 
19750Sstevel@tonic-gate 		get_info(p, mnum);
19760Sstevel@tonic-gate 		if (ddi_copyout((caddr_t)p, data, sizeof (*p), mode) != 0)
19770Sstevel@tonic-gate 			err = EFAULT;
19780Sstevel@tonic-gate 
19790Sstevel@tonic-gate 		md_trans_free(p, sizeof (*p));
19800Sstevel@tonic-gate 		return (err);
19810Sstevel@tonic-gate 	}
19820Sstevel@tonic-gate 
19830Sstevel@tonic-gate 	case DKIOCGGEOM:
19840Sstevel@tonic-gate 	{
19850Sstevel@tonic-gate 		struct dk_geom	*p;
19860Sstevel@tonic-gate 
19870Sstevel@tonic-gate 		if (! (mode & FREAD))
19880Sstevel@tonic-gate 			return (EACCES);
19890Sstevel@tonic-gate 
19900Sstevel@tonic-gate 		if ((p = md_trans_zalloc(sizeof (*p))) == NULL)
19910Sstevel@tonic-gate 			return (ENOMEM);
19920Sstevel@tonic-gate 
19930Sstevel@tonic-gate 		if ((err = trans_get_geom(un, p)) == 0) {
19940Sstevel@tonic-gate 			if (ddi_copyout((caddr_t)p, data, sizeof (*p),
19950Sstevel@tonic-gate 			    mode) != 0)
19960Sstevel@tonic-gate 				err = EFAULT;
19970Sstevel@tonic-gate 		}
19980Sstevel@tonic-gate 
19990Sstevel@tonic-gate 		md_trans_free(p, sizeof (*p));
20000Sstevel@tonic-gate 		return (err);
20010Sstevel@tonic-gate 	}
20020Sstevel@tonic-gate 
20030Sstevel@tonic-gate 	case DKIOCGVTOC:
20040Sstevel@tonic-gate 	{
2005*9017SJohn.Wren.Kennedy@Sun.COM 		struct vtoc	*vtoc;
20060Sstevel@tonic-gate 
20070Sstevel@tonic-gate 		if (! (mode & FREAD))
20080Sstevel@tonic-gate 			return (EACCES);
20090Sstevel@tonic-gate 
2010*9017SJohn.Wren.Kennedy@Sun.COM 		vtoc = kmem_zalloc(sizeof (*vtoc), KM_SLEEP);
2011*9017SJohn.Wren.Kennedy@Sun.COM 		if ((err = trans_get_vtoc(un, vtoc)) != 0) {
2012*9017SJohn.Wren.Kennedy@Sun.COM 			kmem_free(vtoc, sizeof (*vtoc));
20130Sstevel@tonic-gate 			return (err);
20140Sstevel@tonic-gate 		}
20150Sstevel@tonic-gate 
20160Sstevel@tonic-gate 		if ((mode & DATAMODEL_MASK) == DATAMODEL_NATIVE) {
2017*9017SJohn.Wren.Kennedy@Sun.COM 			if (ddi_copyout(vtoc, data, sizeof (*vtoc), mode))
20180Sstevel@tonic-gate 				err = EFAULT;
20190Sstevel@tonic-gate 		}
20200Sstevel@tonic-gate #ifdef _SYSCALL32
20210Sstevel@tonic-gate 		else {
2022*9017SJohn.Wren.Kennedy@Sun.COM 			struct vtoc32	*vtoc32;
2023*9017SJohn.Wren.Kennedy@Sun.COM 
2024*9017SJohn.Wren.Kennedy@Sun.COM 			vtoc32 = kmem_zalloc(sizeof (*vtoc32), KM_SLEEP);
2025*9017SJohn.Wren.Kennedy@Sun.COM 
2026*9017SJohn.Wren.Kennedy@Sun.COM 			vtoctovtoc32((*vtoc), (*vtoc32));
2027*9017SJohn.Wren.Kennedy@Sun.COM 			if (ddi_copyout(vtoc32, data, sizeof (*vtoc32), mode))
20280Sstevel@tonic-gate 				err = EFAULT;
2029*9017SJohn.Wren.Kennedy@Sun.COM 			kmem_free(vtoc32, sizeof (*vtoc32));
20300Sstevel@tonic-gate 		}
20310Sstevel@tonic-gate #endif /* _SYSCALL32 */
20320Sstevel@tonic-gate 
2033*9017SJohn.Wren.Kennedy@Sun.COM 		kmem_free(vtoc, sizeof (*vtoc));
20340Sstevel@tonic-gate 		return (err);
20350Sstevel@tonic-gate 	}
20360Sstevel@tonic-gate 
20370Sstevel@tonic-gate 	case DKIOCSVTOC:
20380Sstevel@tonic-gate 	{
2039*9017SJohn.Wren.Kennedy@Sun.COM 		struct vtoc	*vtoc;
20400Sstevel@tonic-gate 
20410Sstevel@tonic-gate 		if (! (mode & FWRITE))
20420Sstevel@tonic-gate 			return (EACCES);
20430Sstevel@tonic-gate 
2044*9017SJohn.Wren.Kennedy@Sun.COM 		vtoc = kmem_zalloc(sizeof (*vtoc), KM_SLEEP);
20450Sstevel@tonic-gate 		if ((mode & DATAMODEL_MASK) == DATAMODEL_NATIVE) {
2046*9017SJohn.Wren.Kennedy@Sun.COM 			if (ddi_copyin(data, vtoc, sizeof (*vtoc), mode)) {
20470Sstevel@tonic-gate 				err = EFAULT;
20480Sstevel@tonic-gate 			}
20490Sstevel@tonic-gate 		}
20500Sstevel@tonic-gate #ifdef _SYSCALL32
20510Sstevel@tonic-gate 		else {
2052*9017SJohn.Wren.Kennedy@Sun.COM 			struct vtoc32	*vtoc32;
2053*9017SJohn.Wren.Kennedy@Sun.COM 
2054*9017SJohn.Wren.Kennedy@Sun.COM 			vtoc32 = kmem_zalloc(sizeof (*vtoc32), KM_SLEEP);
2055*9017SJohn.Wren.Kennedy@Sun.COM 
2056*9017SJohn.Wren.Kennedy@Sun.COM 			if (ddi_copyin(data, vtoc32, sizeof (*vtoc32), mode)) {
20570Sstevel@tonic-gate 				err = EFAULT;
20580Sstevel@tonic-gate 			} else {
2059*9017SJohn.Wren.Kennedy@Sun.COM 				vtoc32tovtoc((*vtoc32), (*vtoc));
20600Sstevel@tonic-gate 			}
2061*9017SJohn.Wren.Kennedy@Sun.COM 			kmem_free(vtoc32, sizeof (*vtoc32));
20620Sstevel@tonic-gate 		}
20630Sstevel@tonic-gate #endif /* _SYSCALL32 */
20640Sstevel@tonic-gate 
20650Sstevel@tonic-gate 		if (err == 0)
2066*9017SJohn.Wren.Kennedy@Sun.COM 			err = trans_set_vtoc(un, vtoc);
2067*9017SJohn.Wren.Kennedy@Sun.COM 
2068*9017SJohn.Wren.Kennedy@Sun.COM 		kmem_free(vtoc, sizeof (*vtoc));
20690Sstevel@tonic-gate 		return (err);
20700Sstevel@tonic-gate 	}
20710Sstevel@tonic-gate 
20727563SPrasad.Singamsetty@Sun.COM 
20737563SPrasad.Singamsetty@Sun.COM 	case DKIOCGEXTVTOC:
20747563SPrasad.Singamsetty@Sun.COM 	{
2075*9017SJohn.Wren.Kennedy@Sun.COM 		struct extvtoc	*extvtoc;
20767563SPrasad.Singamsetty@Sun.COM 
20777563SPrasad.Singamsetty@Sun.COM 		if (! (mode & FREAD))
20787563SPrasad.Singamsetty@Sun.COM 			return (EACCES);
20797563SPrasad.Singamsetty@Sun.COM 
2080*9017SJohn.Wren.Kennedy@Sun.COM 		extvtoc = kmem_zalloc(sizeof (*extvtoc), KM_SLEEP);
2081*9017SJohn.Wren.Kennedy@Sun.COM 		if ((err = trans_get_extvtoc(un, extvtoc)) != 0) {
20827563SPrasad.Singamsetty@Sun.COM 			return (err);
20837563SPrasad.Singamsetty@Sun.COM 		}
20847563SPrasad.Singamsetty@Sun.COM 
2085*9017SJohn.Wren.Kennedy@Sun.COM 		if (ddi_copyout(extvtoc, data, sizeof (*extvtoc), mode))
20867563SPrasad.Singamsetty@Sun.COM 			err = EFAULT;
20877563SPrasad.Singamsetty@Sun.COM 
2088*9017SJohn.Wren.Kennedy@Sun.COM 		kmem_free(extvtoc, sizeof (*extvtoc));
20897563SPrasad.Singamsetty@Sun.COM 		return (err);
20907563SPrasad.Singamsetty@Sun.COM 	}
20917563SPrasad.Singamsetty@Sun.COM 
20927563SPrasad.Singamsetty@Sun.COM 	case DKIOCSEXTVTOC:
20937563SPrasad.Singamsetty@Sun.COM 	{
2094*9017SJohn.Wren.Kennedy@Sun.COM 		struct extvtoc	*extvtoc;
20957563SPrasad.Singamsetty@Sun.COM 
20967563SPrasad.Singamsetty@Sun.COM 		if (! (mode & FWRITE))
20977563SPrasad.Singamsetty@Sun.COM 			return (EACCES);
20987563SPrasad.Singamsetty@Sun.COM 
2099*9017SJohn.Wren.Kennedy@Sun.COM 		extvtoc = kmem_zalloc(sizeof (*extvtoc), KM_SLEEP);
2100*9017SJohn.Wren.Kennedy@Sun.COM 		if (ddi_copyin(data, extvtoc, sizeof (*extvtoc), mode)) {
21017563SPrasad.Singamsetty@Sun.COM 			err = EFAULT;
21027563SPrasad.Singamsetty@Sun.COM 		}
21037563SPrasad.Singamsetty@Sun.COM 
21047563SPrasad.Singamsetty@Sun.COM 		if (err == 0)
2105*9017SJohn.Wren.Kennedy@Sun.COM 			err = trans_set_extvtoc(un, extvtoc);
2106*9017SJohn.Wren.Kennedy@Sun.COM 
2107*9017SJohn.Wren.Kennedy@Sun.COM 		kmem_free(extvtoc, sizeof (*extvtoc));
21087563SPrasad.Singamsetty@Sun.COM 		return (err);
21097563SPrasad.Singamsetty@Sun.COM 	}
21107563SPrasad.Singamsetty@Sun.COM 
21110Sstevel@tonic-gate 	case DKIOCGAPART:
21120Sstevel@tonic-gate 	{
21130Sstevel@tonic-gate 		struct dk_map	dmp;
21140Sstevel@tonic-gate 
21150Sstevel@tonic-gate 		if ((err = trans_get_cgapart(un, &dmp)) != 0) {
21160Sstevel@tonic-gate 			return (err);
21170Sstevel@tonic-gate 		}
21180Sstevel@tonic-gate 
21190Sstevel@tonic-gate 		if ((mode & DATAMODEL_MASK) == DATAMODEL_NATIVE) {
21200Sstevel@tonic-gate 			if (ddi_copyout((caddr_t)&dmp, data, sizeof (dmp),
21217563SPrasad.Singamsetty@Sun.COM 			    mode) != 0)
21220Sstevel@tonic-gate 				err = EFAULT;
21230Sstevel@tonic-gate 		}
21240Sstevel@tonic-gate #ifdef _SYSCALL32
21250Sstevel@tonic-gate 		else {
21260Sstevel@tonic-gate 			struct dk_map32 dmp32;
21270Sstevel@tonic-gate 
21280Sstevel@tonic-gate 			dmp32.dkl_cylno = dmp.dkl_cylno;
21290Sstevel@tonic-gate 			dmp32.dkl_nblk = dmp.dkl_nblk;
21300Sstevel@tonic-gate 
21310Sstevel@tonic-gate 			if (ddi_copyout((caddr_t)&dmp32, data, sizeof (dmp32),
21327563SPrasad.Singamsetty@Sun.COM 			    mode) != 0)
21330Sstevel@tonic-gate 				err = EFAULT;
21340Sstevel@tonic-gate 		}
21350Sstevel@tonic-gate #endif /* _SYSCALL32 */
21360Sstevel@tonic-gate 
21370Sstevel@tonic-gate 		return (err);
21380Sstevel@tonic-gate 	}
21390Sstevel@tonic-gate 
21400Sstevel@tonic-gate 	/*
21410Sstevel@tonic-gate 	 * _FIOISLOG, _FIOISLOGOK, _FIOLOGRESET are used by fsck/mkfs
21420Sstevel@tonic-gate 	 * after opening the device.  fsck/mkfs use these ioctls for
21430Sstevel@tonic-gate 	 * error recovery.
21440Sstevel@tonic-gate 	 */
21450Sstevel@tonic-gate 	case _FIOISLOG:
21460Sstevel@tonic-gate 		return (trans_islog(un));
21470Sstevel@tonic-gate 
21480Sstevel@tonic-gate 	default:
21490Sstevel@tonic-gate 		return (ENOTTY);
21500Sstevel@tonic-gate 	}
21510Sstevel@tonic-gate }
21520Sstevel@tonic-gate 
21530Sstevel@tonic-gate /*
21540Sstevel@tonic-gate  * rename named service entry points and support functions
21550Sstevel@tonic-gate  */
21560Sstevel@tonic-gate 
21570Sstevel@tonic-gate /* rename/exchange role swap functions */
21580Sstevel@tonic-gate 
21590Sstevel@tonic-gate /*
21600Sstevel@tonic-gate  * MDRNM_UPDATE_SELF
21610Sstevel@tonic-gate  * This role swap function is identical for all unit types,
21620Sstevel@tonic-gate  * so keep it here. It's also the best example because it
21630Sstevel@tonic-gate  * touches all the modified portions of the relevant
21640Sstevel@tonic-gate  * in-common structures.
21650Sstevel@tonic-gate  */
21660Sstevel@tonic-gate void
trans_rename_update_self(md_rendelta_t * delta,md_rentxn_t * rtxnp)21670Sstevel@tonic-gate trans_rename_update_self(
21680Sstevel@tonic-gate 	md_rendelta_t	*delta,
21690Sstevel@tonic-gate 	md_rentxn_t	*rtxnp)
21700Sstevel@tonic-gate {
21710Sstevel@tonic-gate 	minor_t		 from_min, to_min;
21720Sstevel@tonic-gate 	sv_dev_t	 sv;
21730Sstevel@tonic-gate 	mt_unit_t	*un;
21740Sstevel@tonic-gate 
21750Sstevel@tonic-gate 	ASSERT(rtxnp);
21760Sstevel@tonic-gate 	ASSERT(rtxnp->op == MDRNOP_RENAME);
21770Sstevel@tonic-gate 	ASSERT(delta);
21780Sstevel@tonic-gate 	ASSERT(delta->unp);
21790Sstevel@tonic-gate 	ASSERT(delta->uip);
21800Sstevel@tonic-gate 	ASSERT(rtxnp->rec_idx >= 0);
21810Sstevel@tonic-gate 	ASSERT(rtxnp->recids);
21820Sstevel@tonic-gate 	ASSERT(delta->old_role == MDRR_SELF);
21830Sstevel@tonic-gate 	ASSERT(delta->new_role == MDRR_SELF);
21840Sstevel@tonic-gate 
21850Sstevel@tonic-gate 	from_min = rtxnp->from.mnum;
21860Sstevel@tonic-gate 	to_min   = rtxnp->to.mnum;
21870Sstevel@tonic-gate 	un	 = (mt_unit_t *)delta->unp;
21880Sstevel@tonic-gate 
21890Sstevel@tonic-gate 	/*
21900Sstevel@tonic-gate 	 * self id changes in our own unit struct
21910Sstevel@tonic-gate 	 * both mechanisms for identifying the trans must be reset.
21920Sstevel@tonic-gate 	 */
21930Sstevel@tonic-gate 
21940Sstevel@tonic-gate 	MD_SID(delta->unp) = to_min;
21950Sstevel@tonic-gate 	un->un_dev = makedevice(md_major, to_min);
21960Sstevel@tonic-gate 
21970Sstevel@tonic-gate 	/*
21980Sstevel@tonic-gate 	 * clear old array pointers to unit in-core and unit
21990Sstevel@tonic-gate 	 */
22000Sstevel@tonic-gate 
22010Sstevel@tonic-gate 	MDI_VOIDUNIT(from_min) = NULL;
22020Sstevel@tonic-gate 	MD_VOIDUNIT(from_min) = NULL;
22030Sstevel@tonic-gate 
22040Sstevel@tonic-gate 	/*
22050Sstevel@tonic-gate 	 * and point the new slots at the unit in-core and unit structs
22060Sstevel@tonic-gate 	 */
22070Sstevel@tonic-gate 
22080Sstevel@tonic-gate 	MDI_VOIDUNIT(to_min) = delta->uip;
22090Sstevel@tonic-gate 	MD_VOIDUNIT(to_min) = delta->unp;
22100Sstevel@tonic-gate 
22110Sstevel@tonic-gate 	/*
22120Sstevel@tonic-gate 	 * recreate kstats
22130Sstevel@tonic-gate 	 */
22140Sstevel@tonic-gate 	md_kstat_destroy_ui(delta->uip);
22150Sstevel@tonic-gate 	md_kstat_init_ui(to_min, delta->uip);
22160Sstevel@tonic-gate 
22170Sstevel@tonic-gate 	/*
22180Sstevel@tonic-gate 	 * the unit in-core reference to the get next link's id changes
22190Sstevel@tonic-gate 	 */
22200Sstevel@tonic-gate 
22210Sstevel@tonic-gate 	delta->uip->ui_link.ln_id = to_min;
22220Sstevel@tonic-gate 
22230Sstevel@tonic-gate 	/*
22240Sstevel@tonic-gate 	 * name space addition of new key was done from user-level
22250Sstevel@tonic-gate 	 * remove the old name's key here
22260Sstevel@tonic-gate 	 */
22270Sstevel@tonic-gate 
22280Sstevel@tonic-gate 	sv.setno = MD_MIN2SET(from_min);
22290Sstevel@tonic-gate 	sv.key	 = rtxnp->from.key;
22300Sstevel@tonic-gate 
22310Sstevel@tonic-gate 	md_rem_names(&sv, 1);
22320Sstevel@tonic-gate 
22330Sstevel@tonic-gate 
22340Sstevel@tonic-gate 	/*
22350Sstevel@tonic-gate 	 * and store the record id (from the unit struct) into recids
22360Sstevel@tonic-gate 	 * for later commitment by md_rename()
22370Sstevel@tonic-gate 	 */
22380Sstevel@tonic-gate 
22390Sstevel@tonic-gate 	md_store_recid(&rtxnp->rec_idx, rtxnp->recids, delta->unp);
22400Sstevel@tonic-gate }
22410Sstevel@tonic-gate 
22420Sstevel@tonic-gate /*
22430Sstevel@tonic-gate  * MDRNM_UPDATE_KIDS
22440Sstevel@tonic-gate  * rename/exchange of our child or grandchild
22450Sstevel@tonic-gate  */
22460Sstevel@tonic-gate void
trans_renexch_update_kids(md_rendelta_t * delta,md_rentxn_t * rtxnp)22470Sstevel@tonic-gate trans_renexch_update_kids(
22480Sstevel@tonic-gate 	md_rendelta_t	*delta,
22490Sstevel@tonic-gate 	md_rentxn_t	*rtxnp)
22500Sstevel@tonic-gate {
22510Sstevel@tonic-gate 	mt_unit_t	*un;
22520Sstevel@tonic-gate 	minor_t		 from_min, to_min, log_min, master_min;
22530Sstevel@tonic-gate 
22540Sstevel@tonic-gate 	ASSERT(delta);
22550Sstevel@tonic-gate 	ASSERT(rtxnp);
22560Sstevel@tonic-gate 	ASSERT((rtxnp->op == MDRNOP_RENAME) || (rtxnp->op == MDRNOP_EXCHANGE));
22570Sstevel@tonic-gate 	ASSERT(delta->unp);
22580Sstevel@tonic-gate 	ASSERT(rtxnp->recids);
22590Sstevel@tonic-gate 	ASSERT(rtxnp->rec_idx >= 0);
22600Sstevel@tonic-gate 	ASSERT(delta->old_role == MDRR_PARENT);
22610Sstevel@tonic-gate 	ASSERT(delta->new_role == MDRR_PARENT);
22620Sstevel@tonic-gate 
22630Sstevel@tonic-gate 	un		= (mt_unit_t *)delta->unp;
22640Sstevel@tonic-gate 	from_min	= rtxnp->from.mnum;
22650Sstevel@tonic-gate 	to_min		= rtxnp->to.mnum;
22660Sstevel@tonic-gate 	log_min		= md_getminor(un->un_l_dev);
22670Sstevel@tonic-gate 	master_min	= md_getminor(un->un_m_dev);
22680Sstevel@tonic-gate 
22690Sstevel@tonic-gate 	/*
22700Sstevel@tonic-gate 	 * since our role isn't changing (parent->parent)
22710Sstevel@tonic-gate 	 * one of our children must be changing; which one is it?
22720Sstevel@tonic-gate 	 * find the child being modified, and update
22730Sstevel@tonic-gate 	 * our notion of it
22740Sstevel@tonic-gate 	 */
22750Sstevel@tonic-gate 
22760Sstevel@tonic-gate 	/* both devices must be metadevices in order to be updated */
22770Sstevel@tonic-gate 	ASSERT(md_getmajor(un->un_m_dev) == md_major);
22780Sstevel@tonic-gate 	ASSERT(!(un->un_l_unit && (md_getmajor(un->un_l_dev) != md_major)));
22790Sstevel@tonic-gate 
22800Sstevel@tonic-gate 	if ((md_getmajor(un->un_m_dev) == md_major) &&
22817563SPrasad.Singamsetty@Sun.COM 	    (master_min == from_min)) {
22820Sstevel@tonic-gate 
22830Sstevel@tonic-gate 		ASSERT(!(un->un_l_unit && (log_min == from_min)));
22840Sstevel@tonic-gate 
22850Sstevel@tonic-gate 		un->un_m_dev = makedevice(md_major, to_min);
22860Sstevel@tonic-gate 		un->un_m_key = rtxnp->to.key;
22870Sstevel@tonic-gate 
22880Sstevel@tonic-gate 	} else if ((md_getmajor(un->un_m_dev) == md_major) &&
22897563SPrasad.Singamsetty@Sun.COM 	    un->un_l_unit && (log_min == from_min)) {
22900Sstevel@tonic-gate 
22910Sstevel@tonic-gate 		ASSERT(master_min != from_min);
22920Sstevel@tonic-gate 
22930Sstevel@tonic-gate 		un->un_l_dev = makedevice(md_major, to_min);
22940Sstevel@tonic-gate 		un->un_l_key = rtxnp->to.key;
22950Sstevel@tonic-gate 
22960Sstevel@tonic-gate 	} else {
22970Sstevel@tonic-gate 		ASSERT(FALSE);
22980Sstevel@tonic-gate 		panic("trans_renexch_update_kids: not a metadevice");
22990Sstevel@tonic-gate 		/*NOTREACHED*/
23000Sstevel@tonic-gate 	}
23010Sstevel@tonic-gate 
23020Sstevel@tonic-gate 	md_store_recid(&rtxnp->rec_idx, rtxnp->recids, delta->unp);
23030Sstevel@tonic-gate }
23040Sstevel@tonic-gate 
23050Sstevel@tonic-gate /*
23065331Samw  * MDRNM_SELF_UPDATE_FROM (exchange down) [self->child]
23070Sstevel@tonic-gate  */
23080Sstevel@tonic-gate void
trans_exchange_self_update_from_down(md_rendelta_t * delta,md_rentxn_t * rtxnp)23090Sstevel@tonic-gate trans_exchange_self_update_from_down(
23100Sstevel@tonic-gate 	md_rendelta_t	*delta,
23110Sstevel@tonic-gate 	md_rentxn_t	*rtxnp)
23120Sstevel@tonic-gate {
23130Sstevel@tonic-gate 	mt_unit_t	*un;
23140Sstevel@tonic-gate 	minor_t		from_min, to_min, master_min, log_min;
23150Sstevel@tonic-gate 	sv_dev_t	sv;
23160Sstevel@tonic-gate 
23170Sstevel@tonic-gate 	ASSERT(delta);
23180Sstevel@tonic-gate 	ASSERT(delta->unp);
23190Sstevel@tonic-gate 	ASSERT(delta->uip);
23200Sstevel@tonic-gate 	ASSERT(rtxnp);
23210Sstevel@tonic-gate 	ASSERT(MDRNOP_EXCHANGE == rtxnp->op);
23220Sstevel@tonic-gate 	ASSERT(rtxnp->from.uip);
23230Sstevel@tonic-gate 	ASSERT(rtxnp->rec_idx >= 0);
23240Sstevel@tonic-gate 	ASSERT(rtxnp->recids);
23250Sstevel@tonic-gate 	ASSERT(delta->old_role == MDRR_SELF);
23260Sstevel@tonic-gate 	ASSERT(delta->new_role == MDRR_CHILD);
23270Sstevel@tonic-gate 	ASSERT(md_getminor(delta->dev) == rtxnp->from.mnum);
23280Sstevel@tonic-gate 
23290Sstevel@tonic-gate 	un = (mt_unit_t *)delta->unp;
23300Sstevel@tonic-gate 
23310Sstevel@tonic-gate 	/*
23320Sstevel@tonic-gate 	 * if we're exchanging a trans, it had better be a metadevice
23330Sstevel@tonic-gate 	 */
23340Sstevel@tonic-gate 	ASSERT(md_getmajor(un->un_m_dev) == md_major);
23350Sstevel@tonic-gate 
23360Sstevel@tonic-gate 	to_min		= rtxnp->to.mnum;
23370Sstevel@tonic-gate 	from_min	= rtxnp->from.mnum;
23380Sstevel@tonic-gate 	master_min	= md_getminor(un->un_m_dev);
23390Sstevel@tonic-gate 	log_min		= md_getminor(un->un_l_dev);
23400Sstevel@tonic-gate 
23410Sstevel@tonic-gate 	/*
23420Sstevel@tonic-gate 	 * both mechanisms for identifying a trans must be updated
23430Sstevel@tonic-gate 	 */
23440Sstevel@tonic-gate 
23450Sstevel@tonic-gate 	MD_SID(delta->unp) = to_min;
23460Sstevel@tonic-gate 	un->un_dev = makedevice(md_major, to_min);
23470Sstevel@tonic-gate 
23480Sstevel@tonic-gate 	/*
23490Sstevel@tonic-gate 	 * parent identifier need not change
23500Sstevel@tonic-gate 	 */
23510Sstevel@tonic-gate 
23520Sstevel@tonic-gate 	/*
23530Sstevel@tonic-gate 	 * point the set array pointers at the "new" unit and unit in-cores
23540Sstevel@tonic-gate 	 * Note: the other half of this transfer is done in the "update to"
23550Sstevel@tonic-gate 	 * rename/exchange named service.
23560Sstevel@tonic-gate 	 */
23570Sstevel@tonic-gate 
23580Sstevel@tonic-gate 	MDI_VOIDUNIT(to_min) = delta->uip;
23590Sstevel@tonic-gate 	MD_VOIDUNIT(to_min) = delta->unp;
23600Sstevel@tonic-gate 
23610Sstevel@tonic-gate 	/*
23620Sstevel@tonic-gate 	 * transfer kstats
23630Sstevel@tonic-gate 	 */
23640Sstevel@tonic-gate 
23650Sstevel@tonic-gate 	delta->uip->ui_kstat = rtxnp->to.kstatp;
23660Sstevel@tonic-gate 
23670Sstevel@tonic-gate 	/*
23680Sstevel@tonic-gate 	 * the unit in-core reference to the get next link's id changes
23690Sstevel@tonic-gate 	 */
23700Sstevel@tonic-gate 
23710Sstevel@tonic-gate 	delta->uip->ui_link.ln_id = to_min;
23720Sstevel@tonic-gate 
23730Sstevel@tonic-gate 	/*
23740Sstevel@tonic-gate 	 * which one of our children is changing?
23750Sstevel@tonic-gate 	 *
23760Sstevel@tonic-gate 	 * Note that the check routines forbid changing the log (for now)
23770Sstevel@tonic-gate 	 * because there's no lockfs-like trans-ufs "freeze and remount"
23780Sstevel@tonic-gate 	 * or "freeze and bobbit the log."
23790Sstevel@tonic-gate 	 */
23800Sstevel@tonic-gate 
23810Sstevel@tonic-gate 	/* both devices must be metadevices in order to be updated */
23820Sstevel@tonic-gate 	ASSERT(md_getmajor(un->un_m_dev) == md_major);
23837563SPrasad.Singamsetty@Sun.COM 	ASSERT(!(un->un_l_unit && (md_getmajor(un->un_l_dev) != md_major)));
23840Sstevel@tonic-gate 
23850Sstevel@tonic-gate 	if ((md_getmajor(un->un_m_dev) == md_major) &&
23860Sstevel@tonic-gate 	    (master_min == to_min)) {
23870Sstevel@tonic-gate 
23880Sstevel@tonic-gate 		/* master and log can't both be changed */
23890Sstevel@tonic-gate 		ASSERT(!(un->un_l_unit && (log_min == to_min)));
23900Sstevel@tonic-gate 
23910Sstevel@tonic-gate 		un->un_m_dev = makedevice(md_major, from_min);
23920Sstevel@tonic-gate 		sv.key = un->un_m_key;
23930Sstevel@tonic-gate 		un->un_m_key = rtxnp->from.key;
23940Sstevel@tonic-gate 
23950Sstevel@tonic-gate 	} else if ((md_getmajor(un->un_m_dev) == md_major) &&
23967563SPrasad.Singamsetty@Sun.COM 	    un->un_l_unit && (log_min == to_min)) {
23970Sstevel@tonic-gate 
23980Sstevel@tonic-gate 		/* master and log can't both be changed */
23990Sstevel@tonic-gate 		ASSERT(!(master_min == to_min));
24000Sstevel@tonic-gate 
24010Sstevel@tonic-gate 		un->un_l_dev = makedevice(md_major, from_min);
24020Sstevel@tonic-gate 		sv.key = un->un_l_key;
24030Sstevel@tonic-gate 		un->un_l_key = rtxnp->from.key;
24040Sstevel@tonic-gate 
24050Sstevel@tonic-gate 	} else {
24060Sstevel@tonic-gate 		ASSERT(FALSE);
24070Sstevel@tonic-gate 		panic("trans_exchange_self_update_from_down: not a metadevice");
24080Sstevel@tonic-gate 		/*NOTREACHED*/
24090Sstevel@tonic-gate 	}
24100Sstevel@tonic-gate 
24110Sstevel@tonic-gate 	/*
24120Sstevel@tonic-gate 	 * the new master must exist in the name space
24130Sstevel@tonic-gate 	 */
24140Sstevel@tonic-gate 	ASSERT(rtxnp->from.key != MD_KEYWILD);
24150Sstevel@tonic-gate 	ASSERT(rtxnp->from.key != MD_KEYBAD);
24160Sstevel@tonic-gate 
24170Sstevel@tonic-gate 	/*
24180Sstevel@tonic-gate 	 * delete the key for the changed child from the namespace
24190Sstevel@tonic-gate 	 */
24200Sstevel@tonic-gate 
24210Sstevel@tonic-gate 	sv.setno = MD_MIN2SET(from_min);
24220Sstevel@tonic-gate 	md_rem_names(&sv, 1);
24230Sstevel@tonic-gate 
24240Sstevel@tonic-gate 	/*
24250Sstevel@tonic-gate 	 * and store the record id (from the unit struct) into recids
24260Sstevel@tonic-gate 	 */
24270Sstevel@tonic-gate 
24280Sstevel@tonic-gate 	md_store_recid(&rtxnp->rec_idx, rtxnp->recids, delta->unp);
24290Sstevel@tonic-gate }
24300Sstevel@tonic-gate 
24310Sstevel@tonic-gate /*
24325331Samw  * MDRNM_PARENT_UPDATE_TO (exchange down) [parent->self]
24330Sstevel@tonic-gate  */
24340Sstevel@tonic-gate void
trans_exchange_parent_update_to(md_rendelta_t * delta,md_rentxn_t * rtxnp)24350Sstevel@tonic-gate trans_exchange_parent_update_to(
24360Sstevel@tonic-gate 	md_rendelta_t	*delta,
24370Sstevel@tonic-gate 	md_rentxn_t	*rtxnp)
24380Sstevel@tonic-gate {
24390Sstevel@tonic-gate 	mt_unit_t	*un;
24400Sstevel@tonic-gate 	minor_t		from_min, to_min, master_min, log_min;
24410Sstevel@tonic-gate 	sv_dev_t	sv;
24420Sstevel@tonic-gate 
24430Sstevel@tonic-gate 	ASSERT(delta);
24440Sstevel@tonic-gate 	ASSERT(delta->unp);
24450Sstevel@tonic-gate 	ASSERT(delta->uip);
24460Sstevel@tonic-gate 	ASSERT(rtxnp);
24470Sstevel@tonic-gate 	ASSERT(MDRNOP_EXCHANGE == rtxnp->op);
24480Sstevel@tonic-gate 	ASSERT(rtxnp->from.uip);
24490Sstevel@tonic-gate 	ASSERT(rtxnp->rec_idx >= 0);
24500Sstevel@tonic-gate 	ASSERT(rtxnp->recids);
24510Sstevel@tonic-gate 	ASSERT(delta->old_role == MDRR_PARENT);
24520Sstevel@tonic-gate 	ASSERT(delta->new_role == MDRR_SELF);
24530Sstevel@tonic-gate 	ASSERT(md_getminor(delta->dev) == rtxnp->to.mnum);
24540Sstevel@tonic-gate 
24550Sstevel@tonic-gate 	un = (mt_unit_t *)delta->unp;
24560Sstevel@tonic-gate 
24570Sstevel@tonic-gate 	ASSERT(md_getmajor(un->un_m_dev) == md_major);
24580Sstevel@tonic-gate 
24590Sstevel@tonic-gate 	to_min		= rtxnp->to.mnum;
24600Sstevel@tonic-gate 	from_min	= rtxnp->from.mnum;
24610Sstevel@tonic-gate 	master_min	= md_getminor(un->un_m_dev);
24620Sstevel@tonic-gate 	log_min		= md_getminor(un->un_l_dev);
24630Sstevel@tonic-gate 
24640Sstevel@tonic-gate 	/*
24650Sstevel@tonic-gate 	 * both mechanisms for identifying a trans must be updated
24660Sstevel@tonic-gate 	 */
24670Sstevel@tonic-gate 
24680Sstevel@tonic-gate 	MD_SID(delta->unp) = from_min;
24690Sstevel@tonic-gate 	un->un_dev = makedevice(md_major, from_min);
24700Sstevel@tonic-gate 
24710Sstevel@tonic-gate 	/*
24720Sstevel@tonic-gate 	 * parent identifier need not change
24730Sstevel@tonic-gate 	 */
24740Sstevel@tonic-gate 
24750Sstevel@tonic-gate 	/*
24760Sstevel@tonic-gate 	 * point the set array pointers at the "new" unit and unit in-cores
24770Sstevel@tonic-gate 	 * Note: the other half of this transfer is done in the "update to"
24780Sstevel@tonic-gate 	 * rename/exchange named service.
24790Sstevel@tonic-gate 	 */
24800Sstevel@tonic-gate 
24810Sstevel@tonic-gate 	MDI_VOIDUNIT(from_min) = delta->uip;
24820Sstevel@tonic-gate 	MD_VOIDUNIT(from_min) = delta->unp;
24830Sstevel@tonic-gate 
24840Sstevel@tonic-gate 	/*
24850Sstevel@tonic-gate 	 * transfer kstats
24860Sstevel@tonic-gate 	 */
24870Sstevel@tonic-gate 
24880Sstevel@tonic-gate 	delta->uip->ui_kstat = rtxnp->from.kstatp;
24890Sstevel@tonic-gate 
24900Sstevel@tonic-gate 	/*
24910Sstevel@tonic-gate 	 * the unit in-core reference to the get next link's id changes
24920Sstevel@tonic-gate 	 */
24930Sstevel@tonic-gate 
24940Sstevel@tonic-gate 	delta->uip->ui_link.ln_id = from_min;
24950Sstevel@tonic-gate 
24960Sstevel@tonic-gate 	/*
24970Sstevel@tonic-gate 	 * which one of our children is changing?
24980Sstevel@tonic-gate 	 */
24990Sstevel@tonic-gate 
25000Sstevel@tonic-gate 	/* both devices must be metadevices in order to be updated */
25010Sstevel@tonic-gate 	ASSERT(md_getmajor(un->un_m_dev) == md_major);
25027563SPrasad.Singamsetty@Sun.COM 	ASSERT(!(un->un_l_unit && (md_getmajor(un->un_l_dev) != md_major)));
25030Sstevel@tonic-gate 
25040Sstevel@tonic-gate 	if ((md_getmajor(un->un_m_dev) == md_major) &&
25057563SPrasad.Singamsetty@Sun.COM 	    (master_min == from_min)) {
25060Sstevel@tonic-gate 
25070Sstevel@tonic-gate 		/* can't be changing log and master */
25080Sstevel@tonic-gate 		ASSERT(!(un->un_l_unit && (log_min == to_min)));
25090Sstevel@tonic-gate 
25100Sstevel@tonic-gate 		un->un_m_dev = makedevice(md_major, to_min);
25110Sstevel@tonic-gate 		sv.key = un->un_m_key;
25120Sstevel@tonic-gate 		un->un_m_key = rtxnp->to.key;
25130Sstevel@tonic-gate 
25140Sstevel@tonic-gate 	} else if (un->un_l_unit &&
25157563SPrasad.Singamsetty@Sun.COM 	    ((md_getmajor(un->un_l_dev) == md_major) && log_min == to_min)) {
25160Sstevel@tonic-gate 
25170Sstevel@tonic-gate 		/* can't be changing log and master */
25180Sstevel@tonic-gate 		ASSERT(master_min != from_min);
25190Sstevel@tonic-gate 
25200Sstevel@tonic-gate 		un->un_l_dev = makedevice(md_major, to_min);
25210Sstevel@tonic-gate 		sv.key = un->un_l_key;
25220Sstevel@tonic-gate 		un->un_l_key = rtxnp->to.key;
25230Sstevel@tonic-gate 
25240Sstevel@tonic-gate 	} else {
25250Sstevel@tonic-gate 		ASSERT(FALSE);
25260Sstevel@tonic-gate 		panic("trans_exchange_parent_update_to: not a metadevice");
25270Sstevel@tonic-gate 		/*NOTREACHED*/
25280Sstevel@tonic-gate 	}
25290Sstevel@tonic-gate 
25300Sstevel@tonic-gate 	/*
25310Sstevel@tonic-gate 	 * delete the key for the changed child from the namespace
25320Sstevel@tonic-gate 	 */
25330Sstevel@tonic-gate 
25340Sstevel@tonic-gate 	sv.setno = MD_MIN2SET(from_min);
25350Sstevel@tonic-gate 	md_rem_names(&sv, 1);
25360Sstevel@tonic-gate 
25370Sstevel@tonic-gate 	/*
25380Sstevel@tonic-gate 	 * and store the record id (from the unit struct) into recids
25390Sstevel@tonic-gate 	 */
25400Sstevel@tonic-gate 
25410Sstevel@tonic-gate 	md_store_recid(&rtxnp->rec_idx, rtxnp->recids, delta->unp);
25420Sstevel@tonic-gate }
25430Sstevel@tonic-gate 
25440Sstevel@tonic-gate /*
25450Sstevel@tonic-gate  * MDRNM_LIST_URKIDS: named svc entry point
25460Sstevel@tonic-gate  * all all delta entries appropriate for our children onto the
25470Sstevel@tonic-gate  * deltalist pointd to by dlpp
25480Sstevel@tonic-gate  */
25490Sstevel@tonic-gate int
trans_rename_listkids(md_rendelta_t ** dlpp,md_rentxn_t * rtxnp)25500Sstevel@tonic-gate trans_rename_listkids(
25510Sstevel@tonic-gate 	md_rendelta_t	**dlpp,
25520Sstevel@tonic-gate 	md_rentxn_t	 *rtxnp)
25530Sstevel@tonic-gate {
25540Sstevel@tonic-gate 	minor_t		 from_min, to_min, master_min, log_min;
25550Sstevel@tonic-gate 	mt_unit_t	*from_un;
25560Sstevel@tonic-gate 	md_rendelta_t	*new, *p;
25570Sstevel@tonic-gate 	int		 n_children;
25580Sstevel@tonic-gate 
25590Sstevel@tonic-gate 	ASSERT(rtxnp);
25600Sstevel@tonic-gate 	ASSERT(dlpp);
25610Sstevel@tonic-gate 	ASSERT((rtxnp->op == MDRNOP_EXCHANGE) || (rtxnp->op == MDRNOP_RENAME));
25620Sstevel@tonic-gate 
25630Sstevel@tonic-gate 	from_min = rtxnp->from.mnum;
25640Sstevel@tonic-gate 	to_min = rtxnp->to.mnum;
25650Sstevel@tonic-gate 	n_children = 0;
25660Sstevel@tonic-gate 
25670Sstevel@tonic-gate 	if (!MDI_UNIT(from_min) || !(from_un = MD_UNIT(from_min))) {
25680Sstevel@tonic-gate 		(void) mdmderror(&rtxnp->mde, MDE_UNIT_NOT_SETUP, from_min);
25690Sstevel@tonic-gate 		return (-1);
25700Sstevel@tonic-gate 	}
25710Sstevel@tonic-gate 
25720Sstevel@tonic-gate 	for (p = *dlpp; p && p->next != NULL; p = p->next) {
25730Sstevel@tonic-gate 		/* NULL */
25740Sstevel@tonic-gate 	}
25750Sstevel@tonic-gate 
25760Sstevel@tonic-gate 	if (md_getmajor(from_un->un_m_dev) == md_major) {
25770Sstevel@tonic-gate 
25780Sstevel@tonic-gate 		master_min = md_getminor(from_un->un_m_dev);
25790Sstevel@tonic-gate 
25800Sstevel@tonic-gate 		p = new = md_build_rendelta(MDRR_CHILD,
25817563SPrasad.Singamsetty@Sun.COM 		    to_min == master_min? MDRR_SELF: MDRR_CHILD,
25827563SPrasad.Singamsetty@Sun.COM 		    from_un->un_m_dev, p, MD_UNIT(master_min),
25837563SPrasad.Singamsetty@Sun.COM 		    MDI_UNIT(master_min), &rtxnp->mde);
25840Sstevel@tonic-gate 
25850Sstevel@tonic-gate 		if (!new) {
25860Sstevel@tonic-gate 			if (mdisok(&rtxnp->mde)) {
25870Sstevel@tonic-gate 				(void) mdsyserror(&rtxnp->mde, ENOMEM);
25880Sstevel@tonic-gate 			}
25890Sstevel@tonic-gate 			return (-1);
25900Sstevel@tonic-gate 		}
25910Sstevel@tonic-gate 		++n_children;
25920Sstevel@tonic-gate 	}
25930Sstevel@tonic-gate 
25940Sstevel@tonic-gate 	if (from_un->un_l_unit &&
25950Sstevel@tonic-gate 	    (md_getmajor(from_un->un_l_dev) == md_major)) {
25960Sstevel@tonic-gate 
25970Sstevel@tonic-gate 		log_min = md_getminor(from_un->un_l_dev);
25980Sstevel@tonic-gate 
25990Sstevel@tonic-gate 		new = md_build_rendelta(MDRR_CHILD,
26007563SPrasad.Singamsetty@Sun.COM 		    to_min == log_min? MDRR_SELF: MDRR_CHILD,
26017563SPrasad.Singamsetty@Sun.COM 		    from_un->un_l_dev, p, MD_UNIT(log_min),
26027563SPrasad.Singamsetty@Sun.COM 		    MDI_UNIT(log_min), &rtxnp->mde);
26030Sstevel@tonic-gate 		if (!new) {
26040Sstevel@tonic-gate 			if (mdisok(&rtxnp->mde)) {
26050Sstevel@tonic-gate 				(void) mdsyserror(&rtxnp->mde, ENOMEM);
26060Sstevel@tonic-gate 			}
26070Sstevel@tonic-gate 			return (-1);
26080Sstevel@tonic-gate 		}
26090Sstevel@tonic-gate 		++n_children;
26100Sstevel@tonic-gate 	}
26110Sstevel@tonic-gate 
26120Sstevel@tonic-gate 	return (n_children);
26130Sstevel@tonic-gate }
26140Sstevel@tonic-gate 
26150Sstevel@tonic-gate /*
26160Sstevel@tonic-gate  * support routine for MDRNM_CHECK
26170Sstevel@tonic-gate  */
26180Sstevel@tonic-gate static int
trans_may_renexch_self(mt_unit_t * un,mdi_unit_t * ui,md_rentxn_t * rtxnp)26190Sstevel@tonic-gate trans_may_renexch_self(
26200Sstevel@tonic-gate 	mt_unit_t	*un,
26210Sstevel@tonic-gate 	mdi_unit_t	*ui,
26220Sstevel@tonic-gate 	md_rentxn_t	*rtxnp)
26230Sstevel@tonic-gate {
26240Sstevel@tonic-gate 	minor_t			from_min;
26250Sstevel@tonic-gate 	minor_t			to_min;
26260Sstevel@tonic-gate 
26270Sstevel@tonic-gate 	ASSERT(rtxnp);
26280Sstevel@tonic-gate 	ASSERT((rtxnp->op == MDRNOP_RENAME) || (rtxnp->op == MDRNOP_EXCHANGE));
26290Sstevel@tonic-gate 
26300Sstevel@tonic-gate 	from_min = rtxnp->from.mnum;
26310Sstevel@tonic-gate 	to_min	 = rtxnp->to.mnum;
26320Sstevel@tonic-gate 
26330Sstevel@tonic-gate 	if (!un || !ui) {
26340Sstevel@tonic-gate 		(void) mdmderror(&rtxnp->mde, MDE_RENAME_CONFIG_ERROR,
26357563SPrasad.Singamsetty@Sun.COM 		    from_min);
26360Sstevel@tonic-gate 		return (EINVAL);
26370Sstevel@tonic-gate 	}
26380Sstevel@tonic-gate 
26390Sstevel@tonic-gate 	ASSERT(MD_CAPAB(un) & MD_CAN_META_CHILD);
26400Sstevel@tonic-gate 
26410Sstevel@tonic-gate 	if (!(MD_CAPAB(un) & MD_CAN_META_CHILD)) {
26420Sstevel@tonic-gate 		(void) mdmderror(&rtxnp->mde, MDE_RENAME_SOURCE_BAD, from_min);
26430Sstevel@tonic-gate 		return (EINVAL);
26440Sstevel@tonic-gate 	}
26450Sstevel@tonic-gate 
26460Sstevel@tonic-gate 	if (MD_PARENT(un) == MD_MULTI_PARENT) {
26470Sstevel@tonic-gate 		(void) mdmderror(&rtxnp->mde, MDE_RENAME_SOURCE_BAD, from_min);
26480Sstevel@tonic-gate 		return (EINVAL);
26490Sstevel@tonic-gate 	}
26500Sstevel@tonic-gate 
26510Sstevel@tonic-gate 	switch (rtxnp->op) {
26520Sstevel@tonic-gate 	case MDRNOP_EXCHANGE:
26530Sstevel@tonic-gate 		/*
26540Sstevel@tonic-gate 		 * may only swap with our child (master) if it is a metadevice
26550Sstevel@tonic-gate 		 */
26560Sstevel@tonic-gate 		if (md_getmajor(un->un_m_dev) != md_major) {
26570Sstevel@tonic-gate 			(void) mdmderror(&rtxnp->mde, MDE_RENAME_TARGET_BAD,
26587563SPrasad.Singamsetty@Sun.COM 			    to_min);
26590Sstevel@tonic-gate 			return (EINVAL);
26600Sstevel@tonic-gate 		}
26610Sstevel@tonic-gate 
26620Sstevel@tonic-gate 		if (un->un_l_unit &&
26637563SPrasad.Singamsetty@Sun.COM 		    (md_getmajor(un->un_l_dev) != md_major)) {
26640Sstevel@tonic-gate 
26650Sstevel@tonic-gate 			(void) mdmderror(&rtxnp->mde, MDE_RENAME_TARGET_BAD,
26667563SPrasad.Singamsetty@Sun.COM 			    to_min);
26670Sstevel@tonic-gate 			return (EINVAL);
26680Sstevel@tonic-gate 		}
26690Sstevel@tonic-gate 
26700Sstevel@tonic-gate 		if (md_getminor(un->un_m_dev) != to_min) {
26710Sstevel@tonic-gate 			(void) mdmderror(&rtxnp->mde, MDE_RENAME_TARGET_BAD,
26727563SPrasad.Singamsetty@Sun.COM 			    to_min);
26730Sstevel@tonic-gate 			return (EINVAL);
26740Sstevel@tonic-gate 		}
26750Sstevel@tonic-gate 
26760Sstevel@tonic-gate 		break;
26770Sstevel@tonic-gate 
26780Sstevel@tonic-gate 	case MDRNOP_RENAME:
26790Sstevel@tonic-gate 		break;
26800Sstevel@tonic-gate 
26810Sstevel@tonic-gate 	default:
26820Sstevel@tonic-gate 		(void) mdmderror(&rtxnp->mde, MDE_RENAME_CONFIG_ERROR,
26837563SPrasad.Singamsetty@Sun.COM 		    from_min);
26840Sstevel@tonic-gate 		return (EINVAL);
26850Sstevel@tonic-gate 	}
26860Sstevel@tonic-gate 
26870Sstevel@tonic-gate 	return (0);	/* ok */
26880Sstevel@tonic-gate }
26890Sstevel@tonic-gate 
26900Sstevel@tonic-gate /*
26910Sstevel@tonic-gate  * Named service entry point: MDRNM_CHECK
26920Sstevel@tonic-gate  */
26930Sstevel@tonic-gate intptr_t
trans_rename_check(md_rendelta_t * delta,md_rentxn_t * rtxnp)26940Sstevel@tonic-gate trans_rename_check(
26950Sstevel@tonic-gate 	md_rendelta_t	*delta,
26960Sstevel@tonic-gate 	md_rentxn_t	*rtxnp)
26970Sstevel@tonic-gate {
26980Sstevel@tonic-gate 	int		 err = 0;
26990Sstevel@tonic-gate 	mt_unit_t	*un;
27000Sstevel@tonic-gate 
27010Sstevel@tonic-gate 	ASSERT(delta);
27020Sstevel@tonic-gate 	ASSERT(rtxnp);
27030Sstevel@tonic-gate 	ASSERT(delta->unp);
27040Sstevel@tonic-gate 	ASSERT(delta->uip);
27050Sstevel@tonic-gate 	ASSERT((rtxnp->op == MDRNOP_RENAME) || (rtxnp->op == MDRNOP_EXCHANGE));
27060Sstevel@tonic-gate 
27070Sstevel@tonic-gate 	if (!delta || !rtxnp || !delta->unp || !delta->uip) {
27080Sstevel@tonic-gate 		(void) mdsyserror(&rtxnp->mde, EINVAL);
27090Sstevel@tonic-gate 		return (EINVAL);
27100Sstevel@tonic-gate 	}
27110Sstevel@tonic-gate 
27120Sstevel@tonic-gate 	un = (mt_unit_t *)delta->unp;
27130Sstevel@tonic-gate 
27140Sstevel@tonic-gate 	if (rtxnp->revision == MD_RENAME_VERSION_OFFLINE) {
27150Sstevel@tonic-gate 	/*
27160Sstevel@tonic-gate 	 * trans' may not be open, if it is being modified in the exchange
27170Sstevel@tonic-gate 	 * or rename; trans-UFS hasn't been verified to handle the change
27180Sstevel@tonic-gate 	 * out from underneath it.
27190Sstevel@tonic-gate 	 */
27200Sstevel@tonic-gate 		if ((md_unit_isopen(delta->uip)) &&
27210Sstevel@tonic-gate 		    ((md_getminor(delta->dev) == rtxnp->from.mnum) ||
27220Sstevel@tonic-gate 		    (md_getminor(delta->dev) == rtxnp->to.mnum))) {
27230Sstevel@tonic-gate 			(void) mdmderror(&rtxnp->mde,
27247563SPrasad.Singamsetty@Sun.COM 			    MDE_RENAME_BUSY, rtxnp->from.mnum);
27250Sstevel@tonic-gate 			return (EBUSY);
27260Sstevel@tonic-gate 		}
27270Sstevel@tonic-gate 	}
27280Sstevel@tonic-gate 
27290Sstevel@tonic-gate 	/*
27300Sstevel@tonic-gate 	 * can't rename or exchange with a log attached
27310Sstevel@tonic-gate 	 */
27320Sstevel@tonic-gate 
27330Sstevel@tonic-gate 	if (un->un_l_unit) {
27340Sstevel@tonic-gate 		(void) mdmderror(&rtxnp->mde,
27357563SPrasad.Singamsetty@Sun.COM 		    MDE_RENAME_BUSY, rtxnp->from.mnum);
27360Sstevel@tonic-gate 		return (EBUSY);
27370Sstevel@tonic-gate 	}
27380Sstevel@tonic-gate 
27390Sstevel@tonic-gate 	switch (delta->old_role) {
27400Sstevel@tonic-gate 	case MDRR_SELF:
27410Sstevel@tonic-gate 		/*
27420Sstevel@tonic-gate 		 * self does additional checks
27430Sstevel@tonic-gate 		 */
27440Sstevel@tonic-gate 		err = trans_may_renexch_self((mt_unit_t *)delta->unp,
27457563SPrasad.Singamsetty@Sun.COM 		    delta->uip, rtxnp);
27460Sstevel@tonic-gate 		if (err != 0) {
27470Sstevel@tonic-gate 			goto out;
27480Sstevel@tonic-gate 		}
27490Sstevel@tonic-gate 		/* FALLTHROUGH */
27500Sstevel@tonic-gate 
27510Sstevel@tonic-gate 	case MDRR_PARENT:
27520Sstevel@tonic-gate 		/*
27530Sstevel@tonic-gate 		 * top_is_trans is only used to check for online
27540Sstevel@tonic-gate 		 * rename/exchange when MD_RENAME_VERSION == OFFLINE
27550Sstevel@tonic-gate 		 * since trans holds the sub-devices open
27560Sstevel@tonic-gate 		 */
27570Sstevel@tonic-gate 		rtxnp->stat.trans_in_stack = TRUE;
27580Sstevel@tonic-gate 		break;
27590Sstevel@tonic-gate 	default:
27600Sstevel@tonic-gate 		break;
27610Sstevel@tonic-gate 	}
27620Sstevel@tonic-gate out:
27630Sstevel@tonic-gate 	return (err);
27640Sstevel@tonic-gate }
27650Sstevel@tonic-gate 
27660Sstevel@tonic-gate /* end of rename/exchange */
2767