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
51623Stw21770 * Common Development and Distribution License (the "License").
61623Stw21770 * 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 /*
280Sstevel@tonic-gate * Soft partitioning metadevice driver (md_sp), administrative routines.
290Sstevel@tonic-gate *
300Sstevel@tonic-gate * This file contains the administrative routines for the soft partitioning
310Sstevel@tonic-gate * metadevice driver. All administration is done through the use of ioctl's.
320Sstevel@tonic-gate *
330Sstevel@tonic-gate * The primary ioctl's supported by soft partitions are as follows:
340Sstevel@tonic-gate *
350Sstevel@tonic-gate * MD_IOCSET - set up a new soft partition.
360Sstevel@tonic-gate * MD_IOCGET - get the unit structure of a soft partition.
370Sstevel@tonic-gate * MD_IOCRESET - delete a soft partition.
380Sstevel@tonic-gate * MD_IOCGROW - add space to a soft partition.
390Sstevel@tonic-gate * MD_IOCGETDEVS - get the device the soft partition is built on.
400Sstevel@tonic-gate * MD_IOC_SPSTATUS - set the status (un_status field in the soft
410Sstevel@tonic-gate * partition unit structure) for one or more soft
420Sstevel@tonic-gate * partitions.
430Sstevel@tonic-gate *
440Sstevel@tonic-gate * Note that, as with other metadevices, the majority of the work for
450Sstevel@tonic-gate * building/growing/deleting soft partitions is performed in userland
460Sstevel@tonic-gate * (specifically in libmeta, see meta_sp.c). The driver's main administrative
470Sstevel@tonic-gate * function is to maintain the in-core & metadb entries associated with a soft
480Sstevel@tonic-gate * partition.
490Sstevel@tonic-gate *
500Sstevel@tonic-gate * In addition, a few other ioctl's are supported via helper routines in
510Sstevel@tonic-gate * the md driver. These are:
520Sstevel@tonic-gate *
530Sstevel@tonic-gate * DKIOCINFO - get "disk" information.
540Sstevel@tonic-gate * DKIOCGEOM - get geometry information.
550Sstevel@tonic-gate * DKIOCGVTOC - get vtoc information.
560Sstevel@tonic-gate */
570Sstevel@tonic-gate #include <sys/param.h>
580Sstevel@tonic-gate #include <sys/systm.h>
590Sstevel@tonic-gate #include <sys/conf.h>
600Sstevel@tonic-gate #include <sys/file.h>
610Sstevel@tonic-gate #include <sys/user.h>
620Sstevel@tonic-gate #include <sys/uio.h>
630Sstevel@tonic-gate #include <sys/t_lock.h>
640Sstevel@tonic-gate #include <sys/buf.h>
650Sstevel@tonic-gate #include <sys/dkio.h>
660Sstevel@tonic-gate #include <sys/vtoc.h>
670Sstevel@tonic-gate #include <sys/kmem.h>
680Sstevel@tonic-gate #include <vm/page.h>
690Sstevel@tonic-gate #include <sys/sysmacros.h>
700Sstevel@tonic-gate #include <sys/types.h>
710Sstevel@tonic-gate #include <sys/mkdev.h>
720Sstevel@tonic-gate #include <sys/stat.h>
730Sstevel@tonic-gate #include <sys/open.h>
741623Stw21770 #include <sys/lvm/mdvar.h>
750Sstevel@tonic-gate #include <sys/lvm/md_sp.h>
760Sstevel@tonic-gate #include <sys/lvm/md_notify.h>
770Sstevel@tonic-gate #include <sys/modctl.h>
780Sstevel@tonic-gate #include <sys/ddi.h>
790Sstevel@tonic-gate #include <sys/sunddi.h>
800Sstevel@tonic-gate #include <sys/debug.h>
810Sstevel@tonic-gate #include <sys/model.h>
820Sstevel@tonic-gate
830Sstevel@tonic-gate #include <sys/sysevent/eventdefs.h>
840Sstevel@tonic-gate #include <sys/sysevent/svm.h>
850Sstevel@tonic-gate
860Sstevel@tonic-gate extern int md_status;
870Sstevel@tonic-gate
880Sstevel@tonic-gate extern unit_t md_nunits;
890Sstevel@tonic-gate extern set_t md_nsets;
900Sstevel@tonic-gate extern md_set_t md_set[];
910Sstevel@tonic-gate
920Sstevel@tonic-gate extern md_ops_t sp_md_ops;
930Sstevel@tonic-gate extern md_krwlock_t md_unit_array_rw;
940Sstevel@tonic-gate extern major_t md_major;
950Sstevel@tonic-gate
960Sstevel@tonic-gate /*
970Sstevel@tonic-gate * FUNCTION: sp_getun()
980Sstevel@tonic-gate * INPUT: mnum - minor number of soft partition to get.
990Sstevel@tonic-gate * OUTPUT: mde - return error pointer.
1000Sstevel@tonic-gate * RETURNS: mp_unit_t * - ptr to unit structure requested
1010Sstevel@tonic-gate * NULL - error
1020Sstevel@tonic-gate * PURPOSE: Returns a reference to the soft partition unit structure
1030Sstevel@tonic-gate * indicated by the passed-in minor number.
1040Sstevel@tonic-gate */
1050Sstevel@tonic-gate static mp_unit_t *
sp_getun(minor_t mnum,md_error_t * mde)1060Sstevel@tonic-gate sp_getun(minor_t mnum, md_error_t *mde)
1070Sstevel@tonic-gate {
1080Sstevel@tonic-gate mp_unit_t *un;
1090Sstevel@tonic-gate mdi_unit_t *ui;
1100Sstevel@tonic-gate set_t setno = MD_MIN2SET(mnum);
1110Sstevel@tonic-gate
1120Sstevel@tonic-gate /* check set */
1130Sstevel@tonic-gate if ((setno >= md_nsets) || (MD_MIN2UNIT(mnum) >= md_nunits)) {
1140Sstevel@tonic-gate (void) mdmderror(mde, MDE_INVAL_UNIT, mnum);
1150Sstevel@tonic-gate return (NULL);
1160Sstevel@tonic-gate }
1170Sstevel@tonic-gate
1180Sstevel@tonic-gate if (md_get_setstatus(setno) & MD_SET_STALE) {
1190Sstevel@tonic-gate (void) mdmddberror(mde, MDE_DB_STALE, mnum, setno);
1200Sstevel@tonic-gate return (NULL);
1210Sstevel@tonic-gate }
1220Sstevel@tonic-gate
1230Sstevel@tonic-gate ui = MDI_UNIT(mnum);
1240Sstevel@tonic-gate
1250Sstevel@tonic-gate if (ui == NULL) {
1260Sstevel@tonic-gate (void) mdmderror(mde, MDE_UNIT_NOT_SETUP, mnum);
1270Sstevel@tonic-gate return (NULL);
1280Sstevel@tonic-gate }
1290Sstevel@tonic-gate
1300Sstevel@tonic-gate un = (mp_unit_t *)MD_UNIT(mnum);
1310Sstevel@tonic-gate
1320Sstevel@tonic-gate if (un->c.un_type != MD_METASP) {
1330Sstevel@tonic-gate (void) mdmderror(mde, MDE_NOT_SP, mnum);
1340Sstevel@tonic-gate return (NULL);
1350Sstevel@tonic-gate }
1360Sstevel@tonic-gate
1370Sstevel@tonic-gate return (un);
1380Sstevel@tonic-gate }
1390Sstevel@tonic-gate
1400Sstevel@tonic-gate
1410Sstevel@tonic-gate /*
1420Sstevel@tonic-gate * FUNCTION: sp_setstatus()
1430Sstevel@tonic-gate * INPUT: d - data ptr passed in from ioctl.
1440Sstevel@tonic-gate * mode - pass-through to ddi_copyin.
1450Sstevel@tonic-gate * lockp - lock ptr.
1460Sstevel@tonic-gate * OUTPUT: none.
1470Sstevel@tonic-gate * RETURNS: 0 - success.
1480Sstevel@tonic-gate * non-zero - error.
1490Sstevel@tonic-gate * PURPOSE: Set the status of one or more soft partitions atomically.
1500Sstevel@tonic-gate * this implements the MD_IOC_SPSTATUS ioctl. Soft partitions
1510Sstevel@tonic-gate * are passed in as an array of minor numbers. The un_status
1520Sstevel@tonic-gate * field in the unit structure of each soft partition is set to
1530Sstevel@tonic-gate * the status passed in and all unit structures are recommitted
1540Sstevel@tonic-gate * to the metadb at once.
1550Sstevel@tonic-gate */
1560Sstevel@tonic-gate static int
sp_setstatus(void * d,int mode,IOLOCK * lockp)1570Sstevel@tonic-gate sp_setstatus(void *d, int mode, IOLOCK *lockp)
1580Sstevel@tonic-gate {
1590Sstevel@tonic-gate minor_t *minors;
1600Sstevel@tonic-gate mp_unit_t *un;
1610Sstevel@tonic-gate mddb_recid_t *recids;
1620Sstevel@tonic-gate int i, nunits, sz;
1630Sstevel@tonic-gate int err = 0;
1640Sstevel@tonic-gate sp_status_t status;
1650Sstevel@tonic-gate md_error_t *mdep;
1660Sstevel@tonic-gate
1670Sstevel@tonic-gate md_sp_statusset_t *msp = (md_sp_statusset_t *)d;
1680Sstevel@tonic-gate
1690Sstevel@tonic-gate nunits = msp->num_units;
1700Sstevel@tonic-gate sz = msp->size;
1710Sstevel@tonic-gate status = msp->new_status;
1720Sstevel@tonic-gate mdep = &msp->mde;
1730Sstevel@tonic-gate
1740Sstevel@tonic-gate mdclrerror(mdep);
1750Sstevel@tonic-gate /* allocate minor number and recids arrays */
1760Sstevel@tonic-gate minors = kmem_alloc(sz, KM_SLEEP);
1770Sstevel@tonic-gate recids = kmem_alloc((nunits + 1) * sizeof (mddb_recid_t), KM_SLEEP);
1780Sstevel@tonic-gate
1790Sstevel@tonic-gate /* copyin minor number array */
1800Sstevel@tonic-gate if (err = ddi_copyin((void *)(uintptr_t)msp->minors, minors, sz, mode))
1810Sstevel@tonic-gate goto out;
1820Sstevel@tonic-gate
1830Sstevel@tonic-gate /* check to make sure all units are valid first */
1840Sstevel@tonic-gate for (i = 0; i < nunits; i++) {
1850Sstevel@tonic-gate if ((un = sp_getun(minors[i], mdep)) == NULL) {
1860Sstevel@tonic-gate err = mdmderror(mdep, MDE_INVAL_UNIT, minors[i]);
1870Sstevel@tonic-gate goto out;
1880Sstevel@tonic-gate }
1890Sstevel@tonic-gate }
1900Sstevel@tonic-gate
1910Sstevel@tonic-gate /* update state for all units */
1920Sstevel@tonic-gate for (i = 0; i < nunits; i++) {
1930Sstevel@tonic-gate un = sp_getun(minors[i], mdep);
1940Sstevel@tonic-gate (void) md_ioctl_writerlock(lockp, MDI_UNIT(minors[i]));
1950Sstevel@tonic-gate un->un_status = status;
1960Sstevel@tonic-gate recids[i] = un->c.un_record_id;
1970Sstevel@tonic-gate md_ioctl_writerexit(lockp);
1980Sstevel@tonic-gate }
1990Sstevel@tonic-gate
2000Sstevel@tonic-gate recids[i] = 0;
2010Sstevel@tonic-gate mddb_commitrecs_wrapper(recids);
2020Sstevel@tonic-gate
2030Sstevel@tonic-gate out:
2040Sstevel@tonic-gate kmem_free(minors, sz);
2050Sstevel@tonic-gate kmem_free(recids, ((nunits + 1) * sizeof (mddb_recid_t)));
2060Sstevel@tonic-gate return (err);
2070Sstevel@tonic-gate }
2080Sstevel@tonic-gate
2090Sstevel@tonic-gate
2100Sstevel@tonic-gate /*
2110Sstevel@tonic-gate * FUNCTION: sp_update_watermarks()
2120Sstevel@tonic-gate * INPUT: d - data ptr passed in from ioctl.
2130Sstevel@tonic-gate * mode - pass-through to ddi_copyin.
2140Sstevel@tonic-gate * OUTPUT: none.
2150Sstevel@tonic-gate * RETURNS: 0 - success.
2160Sstevel@tonic-gate * non-zero - error.
2170Sstevel@tonic-gate * PURPOSE: This implements the MD_IOC_SPUPDATEWM ioctl.
2180Sstevel@tonic-gate * Watermarks are passed in an array.
2190Sstevel@tonic-gate */
2200Sstevel@tonic-gate static int
sp_update_watermarks(void * d,int mode)2210Sstevel@tonic-gate sp_update_watermarks(void *d, int mode)
2220Sstevel@tonic-gate {
2230Sstevel@tonic-gate minor_t mnum;
2240Sstevel@tonic-gate set_t setno;
2250Sstevel@tonic-gate md_error_t *mdep;
2260Sstevel@tonic-gate mp_unit_t *un;
2270Sstevel@tonic-gate int err = 0;
2280Sstevel@tonic-gate size_t wsz;
2290Sstevel@tonic-gate size_t osz;
2300Sstevel@tonic-gate mp_watermark_t *watermarks;
2310Sstevel@tonic-gate sp_ext_offset_t *offsets;
2320Sstevel@tonic-gate md_dev64_t device;
2330Sstevel@tonic-gate buf_t *bp;
2340Sstevel@tonic-gate int i;
2350Sstevel@tonic-gate md_sp_update_wm_t *mup = (md_sp_update_wm_t *)d;
2360Sstevel@tonic-gate side_t side;
2370Sstevel@tonic-gate
2380Sstevel@tonic-gate mnum = mup->mnum;
2390Sstevel@tonic-gate setno = MD_MIN2SET(mnum);
2400Sstevel@tonic-gate side = mddb_getsidenum(setno);
2410Sstevel@tonic-gate un = MD_UNIT(mnum);
2421623Stw21770
2432063Shshaw if (un == NULL)
2442063Shshaw return (EFAULT);
2451623Stw21770
2460Sstevel@tonic-gate mdep = &mup->mde;
2470Sstevel@tonic-gate
2480Sstevel@tonic-gate mdclrerror(mdep);
2490Sstevel@tonic-gate
2500Sstevel@tonic-gate /* Validate the set */
2510Sstevel@tonic-gate if ((setno >= md_nsets) || (MD_MIN2UNIT(mnum) >= md_nunits))
2520Sstevel@tonic-gate return (mdmderror(mdep, MDE_INVAL_UNIT, mnum));
2530Sstevel@tonic-gate if (md_get_setstatus(setno) & MD_SET_STALE)
2540Sstevel@tonic-gate return (mdmddberror(mdep, MDE_DB_STALE, mnum, setno));
2550Sstevel@tonic-gate
2560Sstevel@tonic-gate wsz = mup->count * sizeof (mp_watermark_t);
2570Sstevel@tonic-gate watermarks = kmem_alloc(wsz, KM_SLEEP);
2580Sstevel@tonic-gate
2590Sstevel@tonic-gate osz = mup->count * sizeof (sp_ext_offset_t);
2600Sstevel@tonic-gate offsets = kmem_alloc(osz, KM_SLEEP);
2610Sstevel@tonic-gate
2620Sstevel@tonic-gate /*
2630Sstevel@tonic-gate * Once we're here, we are no longer stateless: we cannot
2640Sstevel@tonic-gate * return without first freeing the watermarks and offset
2650Sstevel@tonic-gate * arrays we just allocated. So use the "out" label instead
2660Sstevel@tonic-gate * of "return."
2670Sstevel@tonic-gate */
2680Sstevel@tonic-gate
2690Sstevel@tonic-gate /* Retrieve the watermark and offset arrays from user land */
2700Sstevel@tonic-gate
2710Sstevel@tonic-gate if (ddi_copyin((void *)(uintptr_t)mup->wmp, watermarks, wsz, mode)) {
2720Sstevel@tonic-gate err = EFAULT;
2730Sstevel@tonic-gate goto out;
2740Sstevel@tonic-gate }
2750Sstevel@tonic-gate
2760Sstevel@tonic-gate if (ddi_copyin((void *)(uintptr_t)mup->osp, offsets, osz, mode)) {
2770Sstevel@tonic-gate err = EFAULT;
2780Sstevel@tonic-gate goto out;
2790Sstevel@tonic-gate }
2800Sstevel@tonic-gate
2810Sstevel@tonic-gate /*
2820Sstevel@tonic-gate * NOTE: For multi-node sets we only commit the watermarks if we are
2830Sstevel@tonic-gate * the master node. This avoids an ioctl-within-ioctl deadlock if the
2840Sstevel@tonic-gate * underlying device is a mirror.
2850Sstevel@tonic-gate */
2860Sstevel@tonic-gate if (MD_MNSET_SETNO(setno) && !md_set[setno].s_am_i_master) {
2870Sstevel@tonic-gate goto out;
2880Sstevel@tonic-gate }
2890Sstevel@tonic-gate
2900Sstevel@tonic-gate device = un->un_dev;
2910Sstevel@tonic-gate if ((md_getmajor(device) != md_major) &&
2920Sstevel@tonic-gate (md_devid_found(setno, side, un->un_key) == 1)) {
2930Sstevel@tonic-gate device = md_resolve_bydevid(mnum, device, un->un_key);
2940Sstevel@tonic-gate }
2950Sstevel@tonic-gate /*
2960Sstevel@tonic-gate * Flag the fact that we're coming from an ioctl handler to the
2970Sstevel@tonic-gate * underlying device so that it can take appropriate action if needed.
2980Sstevel@tonic-gate * This is necessary for multi-owner mirrors as they may need to
2990Sstevel@tonic-gate * update the metadevice state as a result of the layered open.
3000Sstevel@tonic-gate */
3010Sstevel@tonic-gate if (md_layered_open(mnum, &device, MD_OFLG_FROMIOCTL)) {
3020Sstevel@tonic-gate err = mdcomperror(mdep, MDE_SP_COMP_OPEN_ERR,
3030Sstevel@tonic-gate mnum, device);
3040Sstevel@tonic-gate goto out;
3050Sstevel@tonic-gate }
3060Sstevel@tonic-gate
3070Sstevel@tonic-gate bp = kmem_alloc(biosize(), KM_SLEEP);
3080Sstevel@tonic-gate bioinit(bp);
3090Sstevel@tonic-gate
3100Sstevel@tonic-gate for (i = 0; i < mup->count; i++) {
3110Sstevel@tonic-gate
3120Sstevel@tonic-gate /*
3130Sstevel@tonic-gate * Even the "constant" fields should be initialized
3140Sstevel@tonic-gate * here, since bioreset() below will clear them.
3150Sstevel@tonic-gate */
3160Sstevel@tonic-gate bp->b_flags = B_WRITE;
3170Sstevel@tonic-gate bp->b_bcount = sizeof (mp_watermark_t);
3180Sstevel@tonic-gate bp->b_bufsize = sizeof (mp_watermark_t);
3190Sstevel@tonic-gate bp->b_un.b_addr = (caddr_t)&watermarks[i];
3200Sstevel@tonic-gate bp->b_lblkno = offsets[i];
3210Sstevel@tonic-gate bp->b_edev = md_dev64_to_dev(device);
3220Sstevel@tonic-gate
3230Sstevel@tonic-gate /*
3240Sstevel@tonic-gate * For MN sets only:
3250Sstevel@tonic-gate * Use a special flag MD_STR_WMUPDATE, for the following case:
3260Sstevel@tonic-gate * If the watermarks reside on a mirror disk and a switch
3270Sstevel@tonic-gate * of ownership is triggered by this IO,
3280Sstevel@tonic-gate * the message that is generated by that request must be
3290Sstevel@tonic-gate * processed even if the commd subsystem is currently suspended.
3300Sstevel@tonic-gate *
3310Sstevel@tonic-gate * For non-MN sets or non-mirror metadevices,
3320Sstevel@tonic-gate * this flag has no meaning and is not checked.
3330Sstevel@tonic-gate */
3340Sstevel@tonic-gate
3350Sstevel@tonic-gate md_call_strategy(bp, MD_NOBLOCK | MD_STR_WMUPDATE, NULL);
3360Sstevel@tonic-gate
3370Sstevel@tonic-gate if (biowait(bp)) {
3380Sstevel@tonic-gate err = mdmderror(mdep,
3390Sstevel@tonic-gate MDE_SP_BADWMWRITE, mnum);
3400Sstevel@tonic-gate break;
3410Sstevel@tonic-gate }
3420Sstevel@tonic-gate
3430Sstevel@tonic-gate /* Get the buf_t ready for the next iteration */
3440Sstevel@tonic-gate bioreset(bp);
3450Sstevel@tonic-gate }
3460Sstevel@tonic-gate
3470Sstevel@tonic-gate biofini(bp);
3480Sstevel@tonic-gate kmem_free(bp, biosize());
3490Sstevel@tonic-gate
3500Sstevel@tonic-gate md_layered_close(device, MD_OFLG_NULL);
3510Sstevel@tonic-gate
3520Sstevel@tonic-gate out:
3530Sstevel@tonic-gate kmem_free(watermarks, wsz);
3540Sstevel@tonic-gate kmem_free(offsets, osz);
3550Sstevel@tonic-gate
3560Sstevel@tonic-gate return (err);
3570Sstevel@tonic-gate }
3580Sstevel@tonic-gate
3590Sstevel@tonic-gate
3600Sstevel@tonic-gate /*
3610Sstevel@tonic-gate * FUNCTION: sp_read_watermark()
3620Sstevel@tonic-gate * INPUT: d - data ptr passed in from ioctl.
3630Sstevel@tonic-gate * mode - pass-through to ddi_copyin.
3640Sstevel@tonic-gate * OUTPUT: none.
3650Sstevel@tonic-gate * RETURNS: 0 - success.
3660Sstevel@tonic-gate * non-zero - error.
3670Sstevel@tonic-gate * PURPOSE: This implements the MD_IOC_SPREADWM ioctl.
3680Sstevel@tonic-gate */
3690Sstevel@tonic-gate static int
sp_read_watermark(void * d,int mode)3700Sstevel@tonic-gate sp_read_watermark(void *d, int mode)
3710Sstevel@tonic-gate {
3720Sstevel@tonic-gate md_error_t *mdep;
3730Sstevel@tonic-gate mp_watermark_t watermark;
3740Sstevel@tonic-gate md_dev64_t device;
3750Sstevel@tonic-gate buf_t *bp;
3760Sstevel@tonic-gate md_sp_read_wm_t *mrp = (md_sp_read_wm_t *)d;
3770Sstevel@tonic-gate
3780Sstevel@tonic-gate mdep = &mrp->mde;
3790Sstevel@tonic-gate
3800Sstevel@tonic-gate mdclrerror(mdep);
3810Sstevel@tonic-gate
3820Sstevel@tonic-gate device = mrp->rdev;
3830Sstevel@tonic-gate
3840Sstevel@tonic-gate /*
3850Sstevel@tonic-gate * Flag the fact that we are being called from ioctl context so that
3860Sstevel@tonic-gate * the underlying device can take any necessary extra steps to handle
3870Sstevel@tonic-gate * this scenario.
3880Sstevel@tonic-gate */
3890Sstevel@tonic-gate if (md_layered_open((minor_t)-1, &device, MD_OFLG_FROMIOCTL)) {
3900Sstevel@tonic-gate return (mdcomperror(mdep, MDE_SP_COMP_OPEN_ERR,
3910Sstevel@tonic-gate (minor_t)NODEV, device));
3920Sstevel@tonic-gate }
3930Sstevel@tonic-gate
3940Sstevel@tonic-gate bp = kmem_alloc(biosize(), KM_SLEEP);
3950Sstevel@tonic-gate bioinit(bp);
3960Sstevel@tonic-gate
3970Sstevel@tonic-gate bp->b_flags = B_READ;
3980Sstevel@tonic-gate bp->b_bcount = sizeof (mp_watermark_t);
3990Sstevel@tonic-gate bp->b_bufsize = sizeof (mp_watermark_t);
4000Sstevel@tonic-gate bp->b_un.b_addr = (caddr_t)&watermark;
4010Sstevel@tonic-gate bp->b_lblkno = mrp->offset;
4020Sstevel@tonic-gate bp->b_edev = md_dev64_to_dev(device);
4030Sstevel@tonic-gate
4040Sstevel@tonic-gate md_call_strategy(bp, MD_NOBLOCK, NULL);
4050Sstevel@tonic-gate
4060Sstevel@tonic-gate if (biowait(bp)) {
4070Sstevel@tonic-gate /*
4080Sstevel@tonic-gate * Taking advantage of the knowledge that mdmderror()
4090Sstevel@tonic-gate * returns 0, so we don't really need to keep track of
4100Sstevel@tonic-gate * an error code other than in the error struct.
4110Sstevel@tonic-gate */
4120Sstevel@tonic-gate (void) mdmderror(mdep, MDE_SP_BADWMREAD,
4130Sstevel@tonic-gate getminor(device));
4140Sstevel@tonic-gate }
4150Sstevel@tonic-gate
4160Sstevel@tonic-gate biofini(bp);
4170Sstevel@tonic-gate kmem_free(bp, biosize());
4180Sstevel@tonic-gate
4190Sstevel@tonic-gate md_layered_close(device, MD_OFLG_NULL);
4200Sstevel@tonic-gate
4210Sstevel@tonic-gate if (ddi_copyout(&watermark, (void *)(uintptr_t)mrp->wmp,
4220Sstevel@tonic-gate sizeof (mp_watermark_t), mode)) {
4230Sstevel@tonic-gate return (EFAULT);
4240Sstevel@tonic-gate }
4250Sstevel@tonic-gate
4260Sstevel@tonic-gate return (0);
4270Sstevel@tonic-gate }
4280Sstevel@tonic-gate
4290Sstevel@tonic-gate
4300Sstevel@tonic-gate /*
4310Sstevel@tonic-gate * FUNCTION: sp_set()
4320Sstevel@tonic-gate * INPUT: d - data ptr passed in from ioctl.
4330Sstevel@tonic-gate * mode - pass-through to ddi_copyin.
4340Sstevel@tonic-gate * OUTPUT: none.
4350Sstevel@tonic-gate * RETURNS: 0 - success.
4360Sstevel@tonic-gate * non-zero - error.
4370Sstevel@tonic-gate * PURPOSE: Create a soft partition. The unit structure representing
4380Sstevel@tonic-gate * the soft partiton is passed down from userland. We allocate
4390Sstevel@tonic-gate * a metadb entry, copyin the unit the structure, handle any
4400Sstevel@tonic-gate * metadevice parenting issues, then commit the record to the
4410Sstevel@tonic-gate * metadb. Once the record is in the metadb, we must also
4420Sstevel@tonic-gate * build the associated in-core structures. This is done via
4430Sstevel@tonic-gate * sp_build_incore() (see sp.c).
4440Sstevel@tonic-gate */
4450Sstevel@tonic-gate static int
sp_set(void * d,int mode)4460Sstevel@tonic-gate sp_set(void *d, int mode)
4470Sstevel@tonic-gate {
4480Sstevel@tonic-gate minor_t mnum;
4490Sstevel@tonic-gate mp_unit_t *un;
4500Sstevel@tonic-gate void *rec_addr;
4510Sstevel@tonic-gate mddb_recid_t recids[3];
4520Sstevel@tonic-gate mddb_type_t rec_type;
4530Sstevel@tonic-gate int err;
4540Sstevel@tonic-gate set_t setno;
4550Sstevel@tonic-gate md_error_t *mdep;
4560Sstevel@tonic-gate md_unit_t *child_un;
4570Sstevel@tonic-gate md_set_params_t *msp = (md_set_params_t *)d;
4580Sstevel@tonic-gate
4590Sstevel@tonic-gate mnum = msp->mnum;
4600Sstevel@tonic-gate setno = MD_MIN2SET(mnum);
4610Sstevel@tonic-gate mdep = &msp->mde;
4620Sstevel@tonic-gate
4630Sstevel@tonic-gate mdclrerror(mdep);
4640Sstevel@tonic-gate
4650Sstevel@tonic-gate /* validate set */
4660Sstevel@tonic-gate
4670Sstevel@tonic-gate if ((setno >= md_nsets) || (MD_MIN2UNIT(mnum) >= md_nunits))
4680Sstevel@tonic-gate return (mdmderror(mdep, MDE_INVAL_UNIT, mnum));
4690Sstevel@tonic-gate if (md_get_setstatus(setno) & MD_SET_STALE)
4700Sstevel@tonic-gate return (mdmddberror(mdep, MDE_DB_STALE, mnum, setno));
4710Sstevel@tonic-gate
4720Sstevel@tonic-gate /* get the record type */
4730Sstevel@tonic-gate rec_type = (mddb_type_t)md_getshared_key(setno,
4740Sstevel@tonic-gate sp_md_ops.md_driver.md_drivername);
4750Sstevel@tonic-gate
4760Sstevel@tonic-gate /* check if there is already a device with this minor number */
4770Sstevel@tonic-gate un = MD_UNIT(mnum);
4780Sstevel@tonic-gate if (un != NULL)
4790Sstevel@tonic-gate return (mdmderror(mdep, MDE_UNIT_ALREADY_SETUP, mnum));
4800Sstevel@tonic-gate
4810Sstevel@tonic-gate /* create the db record for this soft partition */
4820Sstevel@tonic-gate
4830Sstevel@tonic-gate if (msp->options & MD_CRO_64BIT) {
4840Sstevel@tonic-gate #if defined(_ILP32)
4850Sstevel@tonic-gate return (mdmderror(mdep, MDE_UNIT_TOO_LARGE, mnum));
4860Sstevel@tonic-gate #else
4871623Stw21770 recids[0] = mddb_createrec((size_t)msp->size, rec_type, 0,
4887563SPrasad.Singamsetty@Sun.COM MD_CRO_64BIT | MD_CRO_SOFTPART | MD_CRO_FN, setno);
4890Sstevel@tonic-gate #endif
4900Sstevel@tonic-gate } else {
4911623Stw21770 recids[0] = mddb_createrec((size_t)msp->size, rec_type, 0,
4927563SPrasad.Singamsetty@Sun.COM MD_CRO_32BIT | MD_CRO_SOFTPART | MD_CRO_FN, setno);
4930Sstevel@tonic-gate }
4940Sstevel@tonic-gate /* set initial value for possible child record */
4950Sstevel@tonic-gate recids[1] = 0;
4960Sstevel@tonic-gate if (recids[0] < 0)
4970Sstevel@tonic-gate return (mddbstatus2error(mdep, recids[0], mnum, setno));
4980Sstevel@tonic-gate
4990Sstevel@tonic-gate /* get the address of the soft partition db record */
5000Sstevel@tonic-gate rec_addr = (void *) mddb_getrecaddr(recids[0]);
5010Sstevel@tonic-gate
5020Sstevel@tonic-gate /*
5030Sstevel@tonic-gate * at this point we can happily mess with the soft partition
5040Sstevel@tonic-gate * db record since we haven't committed it to the metadb yet.
5050Sstevel@tonic-gate * if we crash before we commit, the uncommitted record will be
5060Sstevel@tonic-gate * automatically purged.
5070Sstevel@tonic-gate */
5080Sstevel@tonic-gate
5090Sstevel@tonic-gate /* copy in the user's soft partition unit struct */
5100Sstevel@tonic-gate if (err = ddi_copyin((void *)(uintptr_t)msp->mdp,
5110Sstevel@tonic-gate rec_addr, (size_t)msp->size, mode)) {
5120Sstevel@tonic-gate mddb_deleterec_wrapper(recids[0]);
5130Sstevel@tonic-gate return (EFAULT);
5140Sstevel@tonic-gate }
5150Sstevel@tonic-gate
5160Sstevel@tonic-gate /* fill in common unit structure fields which aren't set in userland */
5170Sstevel@tonic-gate un = (mp_unit_t *)rec_addr;
5180Sstevel@tonic-gate
5190Sstevel@tonic-gate /* All 64 bit metadevices only support EFI labels. */
5200Sstevel@tonic-gate if (msp->options & MD_CRO_64BIT) {
5210Sstevel@tonic-gate un->c.un_flag |= MD_EFILABEL;
5220Sstevel@tonic-gate }
5230Sstevel@tonic-gate
5240Sstevel@tonic-gate MD_SID(un) = mnum;
5250Sstevel@tonic-gate MD_RECID(un) = recids[0];
5260Sstevel@tonic-gate MD_PARENT(un) = MD_NO_PARENT;
5271623Stw21770 un->c.un_revision |= MD_FN_META_DEV;
5280Sstevel@tonic-gate
5290Sstevel@tonic-gate /* if we are parenting a metadevice, set our child's parent field */
5300Sstevel@tonic-gate if (md_getmajor(un->un_dev) == md_major) {
5310Sstevel@tonic-gate /* it's a metadevice, need to parent it */
5320Sstevel@tonic-gate child_un = MD_UNIT(md_getminor(un->un_dev));
5330Sstevel@tonic-gate if (child_un == NULL) {
5340Sstevel@tonic-gate mddb_deleterec_wrapper(recids[0]);
5350Sstevel@tonic-gate return (mdmderror(mdep, MDE_INVAL_UNIT,
5360Sstevel@tonic-gate md_getminor(un->un_dev)));
5370Sstevel@tonic-gate }
5380Sstevel@tonic-gate md_set_parent(un->un_dev, MD_SID(un));
5390Sstevel@tonic-gate
5400Sstevel@tonic-gate /* set child recid and recids end marker */
5410Sstevel@tonic-gate recids[1] = MD_RECID(child_un);
5420Sstevel@tonic-gate recids[2] = 0;
5430Sstevel@tonic-gate }
5440Sstevel@tonic-gate
5450Sstevel@tonic-gate /*
5460Sstevel@tonic-gate * build the incore structures.
5470Sstevel@tonic-gate */
5480Sstevel@tonic-gate if (err = sp_build_incore(rec_addr, 0)) {
5497627SChris.Horne@Sun.COM md_nblocks_set(mnum, -1ULL);
5500Sstevel@tonic-gate MD_UNIT(mnum) = NULL;
5517627SChris.Horne@Sun.COM
5520Sstevel@tonic-gate mddb_deleterec_wrapper(recids[0]);
5530Sstevel@tonic-gate return (err);
5540Sstevel@tonic-gate }
5550Sstevel@tonic-gate
5560Sstevel@tonic-gate /*
5571623Stw21770 * Update unit availability
5581623Stw21770 */
5591623Stw21770 md_set[setno].s_un_avail--;
5601623Stw21770
5611623Stw21770 /*
5620Sstevel@tonic-gate * commit the record.
5630Sstevel@tonic-gate * if we had to update a child record, it will get commited
5640Sstevel@tonic-gate * as well.
5650Sstevel@tonic-gate */
5660Sstevel@tonic-gate mddb_commitrecs_wrapper(recids);
5670Sstevel@tonic-gate
5680Sstevel@tonic-gate /* create the mdi_unit struct for this soft partition */
5690Sstevel@tonic-gate md_create_unit_incore(mnum, &sp_md_ops, 0);
5700Sstevel@tonic-gate
5710Sstevel@tonic-gate SE_NOTIFY(EC_SVM_CONFIG, ESC_SVM_CREATE, TAG_METADEVICE, MD_UN2SET(un),
5720Sstevel@tonic-gate MD_SID(un));
5730Sstevel@tonic-gate return (0);
5740Sstevel@tonic-gate }
5750Sstevel@tonic-gate
5760Sstevel@tonic-gate
5770Sstevel@tonic-gate /*
5780Sstevel@tonic-gate * FUNCTION: sp_get()
5790Sstevel@tonic-gate * INPUT: d - data ptr.
5800Sstevel@tonic-gate * mode - pass-through to ddi_copyout.
5810Sstevel@tonic-gate * lock - lock ptr.
5820Sstevel@tonic-gate * OUTPUT: none.
5830Sstevel@tonic-gate * RETURNS: 0 - success.
5840Sstevel@tonic-gate * non-zero - error.
5850Sstevel@tonic-gate * PURPOSE: Get the soft partition unit structure specified by the
5860Sstevel@tonic-gate * minor number. the in-core unit structure is obtained
5870Sstevel@tonic-gate * and copied into the md_i_get structure passed down from
5880Sstevel@tonic-gate * userland.
5890Sstevel@tonic-gate */
5900Sstevel@tonic-gate static int
sp_get(void * d,int mode,IOLOCK * lock)5910Sstevel@tonic-gate sp_get(void *d, int mode, IOLOCK *lock)
5920Sstevel@tonic-gate {
5930Sstevel@tonic-gate minor_t mnum;
5940Sstevel@tonic-gate mdi_unit_t *ui;
5950Sstevel@tonic-gate mp_unit_t *un;
5960Sstevel@tonic-gate md_error_t *mdep;
5970Sstevel@tonic-gate md_i_get_t *migp = d;
5980Sstevel@tonic-gate
5990Sstevel@tonic-gate
6000Sstevel@tonic-gate mnum = migp->id;
6010Sstevel@tonic-gate mdep = &migp->mde;
6020Sstevel@tonic-gate
6030Sstevel@tonic-gate mdclrerror(mdep);
6040Sstevel@tonic-gate
6050Sstevel@tonic-gate /* make sure this is a valid unit structure */
6060Sstevel@tonic-gate if ((MD_MIN2SET(mnum) >= md_nsets) || (MD_MIN2UNIT(mnum) >= md_nunits))
6070Sstevel@tonic-gate return (mdmderror(mdep, MDE_INVAL_UNIT, mnum));
6080Sstevel@tonic-gate
6090Sstevel@tonic-gate /* get the mdi_unit */
6100Sstevel@tonic-gate if ((ui = MDI_UNIT(mnum)) == NULL) {
6110Sstevel@tonic-gate return (mdmderror(mdep, MDE_UNIT_NOT_SETUP, mnum));
6120Sstevel@tonic-gate }
6130Sstevel@tonic-gate
6140Sstevel@tonic-gate /*
6150Sstevel@tonic-gate * md_ioctl_readerlock returns a reference to the in-core
6160Sstevel@tonic-gate * unit structure. this lock will be dropped by
6170Sstevel@tonic-gate * md_ioctl_lock_exit() before the ioctl returns.
6180Sstevel@tonic-gate */
6190Sstevel@tonic-gate un = (mp_unit_t *)md_ioctl_readerlock(lock, ui);
6200Sstevel@tonic-gate
6210Sstevel@tonic-gate /* verify the md_i_get structure */
6220Sstevel@tonic-gate if (migp->size == 0) {
6230Sstevel@tonic-gate migp->size = un->c.un_size;
6240Sstevel@tonic-gate return (0);
6250Sstevel@tonic-gate }
6260Sstevel@tonic-gate if (migp->size < un->c.un_size) {
6270Sstevel@tonic-gate return (EFAULT);
6280Sstevel@tonic-gate }
6290Sstevel@tonic-gate
6300Sstevel@tonic-gate /* copyout unit */
6310Sstevel@tonic-gate if (ddi_copyout(un, (void *)(uintptr_t)migp->mdp,
6320Sstevel@tonic-gate un->c.un_size, mode))
6330Sstevel@tonic-gate return (EFAULT);
6340Sstevel@tonic-gate return (0);
6350Sstevel@tonic-gate }
6360Sstevel@tonic-gate
6370Sstevel@tonic-gate
6380Sstevel@tonic-gate /*
6390Sstevel@tonic-gate * FUNCTION: sp_reset()
6400Sstevel@tonic-gate * INPUT: reset_params - soft partitioning reset parameters.
6410Sstevel@tonic-gate * OUTPUT: none.
6420Sstevel@tonic-gate * RETURNS: 0 - success.
6430Sstevel@tonic-gate * non-zero - error.
6440Sstevel@tonic-gate * PURPOSE: Do the setup work needed to delete a soft partition.
6450Sstevel@tonic-gate * note that the actual removal of both in-core and metadb
6460Sstevel@tonic-gate * structures is done in the reset_sp() routine (see sp.c).
6470Sstevel@tonic-gate * In addition, since multiple soft partitions may exist
6480Sstevel@tonic-gate * on top of a single metadevice, the soft partition reset
6490Sstevel@tonic-gate * parameters (md_sp_reset_t) contains information about
6500Sstevel@tonic-gate * how the soft partition should deparent/reparent the
6510Sstevel@tonic-gate * underlying metadevice. If the underlying metadevice is
6520Sstevel@tonic-gate * to be deparented, the new_parent field will be MD_NO_PARENT,
6530Sstevel@tonic-gate * otherwise it will be contain the minor number of another
6540Sstevel@tonic-gate * soft partition built on top of the underlying metadevice.
6550Sstevel@tonic-gate */
6560Sstevel@tonic-gate static int
sp_reset(md_sp_reset_t * softp)6570Sstevel@tonic-gate sp_reset(md_sp_reset_t *softp)
6580Sstevel@tonic-gate {
6590Sstevel@tonic-gate minor_t mnum = softp->mnum;
6600Sstevel@tonic-gate mdi_unit_t *ui;
6610Sstevel@tonic-gate mp_unit_t *un;
6620Sstevel@tonic-gate md_unit_t *child_un;
6631623Stw21770 set_t setno = MD_MIN2SET(mnum);
6640Sstevel@tonic-gate
6650Sstevel@tonic-gate mdclrerror(&softp->mde);
6660Sstevel@tonic-gate
6670Sstevel@tonic-gate /* get the unit structure */
6680Sstevel@tonic-gate if ((un = sp_getun(mnum, &softp->mde)) == NULL) {
6690Sstevel@tonic-gate return (mdmderror(&softp->mde, MDE_INVAL_UNIT, mnum));
6700Sstevel@tonic-gate }
6710Sstevel@tonic-gate
6720Sstevel@tonic-gate /* don't delete if we have a parent */
6730Sstevel@tonic-gate if (MD_HAS_PARENT(un->c.un_parent)) {
6740Sstevel@tonic-gate return (mdmderror(&softp->mde, MDE_IN_USE, mnum));
6750Sstevel@tonic-gate }
6760Sstevel@tonic-gate
6770Sstevel@tonic-gate rw_enter(&md_unit_array_rw.lock, RW_WRITER);
6780Sstevel@tonic-gate
6790Sstevel@tonic-gate ui = MDI_UNIT(mnum);
6800Sstevel@tonic-gate (void) md_unit_openclose_enter(ui);
6810Sstevel@tonic-gate
6820Sstevel@tonic-gate /* don't delete if we are currently open */
6830Sstevel@tonic-gate if (md_unit_isopen(ui)) {
6840Sstevel@tonic-gate md_unit_openclose_exit(ui);
6850Sstevel@tonic-gate rw_exit(&md_unit_array_rw.lock);
6860Sstevel@tonic-gate return (mdmderror(&softp->mde, MDE_IS_OPEN, mnum));
6870Sstevel@tonic-gate }
6880Sstevel@tonic-gate
6890Sstevel@tonic-gate md_unit_openclose_exit(ui);
6900Sstevel@tonic-gate
6910Sstevel@tonic-gate /*
6920Sstevel@tonic-gate * if we are built on metadevice, we need to deparent
6930Sstevel@tonic-gate * or reparent that metadevice.
6940Sstevel@tonic-gate */
6950Sstevel@tonic-gate if (md_getmajor(un->un_dev) == md_major) {
6960Sstevel@tonic-gate child_un = MD_UNIT(md_getminor(un->un_dev));
6970Sstevel@tonic-gate md_set_parent(un->un_dev, softp->new_parent);
6980Sstevel@tonic-gate mddb_commitrec_wrapper(MD_RECID(child_un));
6990Sstevel@tonic-gate }
7000Sstevel@tonic-gate /* remove the soft partition */
7010Sstevel@tonic-gate reset_sp(un, mnum, 1);
7020Sstevel@tonic-gate
7031623Stw21770 /*
7041623Stw21770 * Update unit availability
7051623Stw21770 */
7061623Stw21770 md_set[setno].s_un_avail++;
7071623Stw21770
7081623Stw21770 /*
7091623Stw21770 * If MN set, reset s_un_next so all nodes can have
7101623Stw21770 * the same view of the next available slot when
7111623Stw21770 * nodes are -w and -j
7121623Stw21770 */
7131623Stw21770 if (MD_MNSET_SETNO(setno)) {
7141623Stw21770 md_upd_set_unnext(setno, MD_MIN2UNIT(mnum));
7151623Stw21770 }
7161623Stw21770
7170Sstevel@tonic-gate /* release locks and return */
7180Sstevel@tonic-gate out:
7190Sstevel@tonic-gate rw_exit(&md_unit_array_rw.lock);
7200Sstevel@tonic-gate return (0);
7210Sstevel@tonic-gate }
7220Sstevel@tonic-gate
7230Sstevel@tonic-gate
7240Sstevel@tonic-gate /*
7250Sstevel@tonic-gate * FUNCTION: sp_grow()
7260Sstevel@tonic-gate * INPUT: d - data ptr.
7270Sstevel@tonic-gate * mode - pass-through to ddi_copyin.
7280Sstevel@tonic-gate * lockp - lock ptr.
7290Sstevel@tonic-gate * OUTPUT: none.
7300Sstevel@tonic-gate * RETURNS: 0 - success.
7310Sstevel@tonic-gate * non-zero - error.
7320Sstevel@tonic-gate * PURPOSE: Attach more space to a soft partition. We are passed in
7330Sstevel@tonic-gate * a new unit structure with the new extents and other updated
7340Sstevel@tonic-gate * information. The new unit structure essentially replaces
7350Sstevel@tonic-gate * the old unit for this soft partition. We place the new
7360Sstevel@tonic-gate * unit into the metadb, delete the old metadb record, and
7370Sstevel@tonic-gate * then update the in-core unit structure array to point to
7380Sstevel@tonic-gate * the new unit.
7390Sstevel@tonic-gate */
7400Sstevel@tonic-gate static int
sp_grow(void * d,int mode,IOLOCK * lockp)7410Sstevel@tonic-gate sp_grow(void *d, int mode, IOLOCK *lockp)
7420Sstevel@tonic-gate {
7430Sstevel@tonic-gate minor_t mnum;
7440Sstevel@tonic-gate mp_unit_t *un, *new_un;
7450Sstevel@tonic-gate mdi_unit_t *ui;
7460Sstevel@tonic-gate minor_t *par = NULL;
7470Sstevel@tonic-gate IOLOCK *plock = NULL;
7480Sstevel@tonic-gate int i;
7490Sstevel@tonic-gate mddb_recid_t recid;
7500Sstevel@tonic-gate mddb_type_t rec_type;
7510Sstevel@tonic-gate mddb_recid_t old_vtoc = 0;
7521623Stw21770 md_create_rec_option_t options;
7530Sstevel@tonic-gate int err;
7540Sstevel@tonic-gate int rval = 0;
7550Sstevel@tonic-gate set_t setno;
7560Sstevel@tonic-gate md_error_t *mdep;
7570Sstevel@tonic-gate int npar;
7580Sstevel@tonic-gate md_grow_params_t *mgp = (md_grow_params_t *)d;
7590Sstevel@tonic-gate
7600Sstevel@tonic-gate mnum = mgp->mnum;
7610Sstevel@tonic-gate mdep = &mgp->mde;
7620Sstevel@tonic-gate setno = MD_MIN2SET(mnum);
7630Sstevel@tonic-gate npar = mgp->npar;
7640Sstevel@tonic-gate
7650Sstevel@tonic-gate mdclrerror(mdep);
7660Sstevel@tonic-gate
7670Sstevel@tonic-gate /* validate set */
7680Sstevel@tonic-gate if ((setno >= md_nsets) || (MD_MIN2UNIT(mnum) >= md_nunits))
7690Sstevel@tonic-gate return (mdmderror(mdep, MDE_INVAL_UNIT, mnum));
7700Sstevel@tonic-gate if (md_get_setstatus(setno) & MD_SET_STALE)
7710Sstevel@tonic-gate return (mdmddberror(mdep, MDE_DB_STALE, mnum, setno));
7720Sstevel@tonic-gate
7730Sstevel@tonic-gate /* make sure this soft partition already exists */
7740Sstevel@tonic-gate ui = MDI_UNIT(mnum);
7750Sstevel@tonic-gate if (ui == NULL)
7760Sstevel@tonic-gate return (mdmderror(mdep, MDE_UNIT_NOT_SETUP, mnum));
7770Sstevel@tonic-gate
7780Sstevel@tonic-gate /* handle any parents */
7790Sstevel@tonic-gate if (npar >= 1) {
7800Sstevel@tonic-gate ASSERT((minor_t *)(uintptr_t)mgp->par != NULL);
7810Sstevel@tonic-gate par = kmem_alloc(npar * sizeof (*par), KM_SLEEP);
7820Sstevel@tonic-gate plock = kmem_alloc(npar * sizeof (*plock), KM_SLEEP);
7830Sstevel@tonic-gate if (ddi_copyin((void *)(uintptr_t)mgp->par, par,
7840Sstevel@tonic-gate (npar * sizeof (*par)), mode) != 0) {
7850Sstevel@tonic-gate kmem_free(par, npar * sizeof (*par));
7860Sstevel@tonic-gate kmem_free(plock, npar * sizeof (*plock));
7870Sstevel@tonic-gate return (EFAULT);
7880Sstevel@tonic-gate }
7890Sstevel@tonic-gate }
7900Sstevel@tonic-gate
7910Sstevel@tonic-gate /*
7920Sstevel@tonic-gate * handle parent locking. grab the unit writer lock,
7930Sstevel@tonic-gate * then all parent ioctl locks, and then finally our own.
7940Sstevel@tonic-gate * parents should be sorted to avoid deadlock.
7950Sstevel@tonic-gate */
7960Sstevel@tonic-gate rw_enter(&md_unit_array_rw.lock, RW_WRITER);
7970Sstevel@tonic-gate for (i = 0; i < npar; ++i) {
7980Sstevel@tonic-gate (void) md_ioctl_writerlock(&plock[i],
7990Sstevel@tonic-gate MDI_UNIT(par[i]));
8000Sstevel@tonic-gate }
8010Sstevel@tonic-gate un = (mp_unit_t *)md_ioctl_writerlock(lockp, ui);
8020Sstevel@tonic-gate
8030Sstevel@tonic-gate rec_type = (mddb_type_t)md_getshared_key(setno,
8040Sstevel@tonic-gate sp_md_ops.md_driver.md_drivername);
8050Sstevel@tonic-gate
8061623Stw21770 /*
8071623Stw21770 * Preserve the friendly name nature of the unit that is growing.
8081623Stw21770 */
8091623Stw21770 options = MD_CRO_SOFTPART;
8101623Stw21770 if (un->c.un_revision & MD_FN_META_DEV)
8111623Stw21770 options |= MD_CRO_FN;
8120Sstevel@tonic-gate if (mgp->options & MD_CRO_64BIT) {
8130Sstevel@tonic-gate #if defined(_ILP32)
8140Sstevel@tonic-gate rval = mdmderror(mdep, MDE_UNIT_TOO_LARGE, mnum);
8150Sstevel@tonic-gate goto out;
8160Sstevel@tonic-gate #else
8170Sstevel@tonic-gate recid = mddb_createrec((size_t)mgp->size, rec_type, 0,
8187563SPrasad.Singamsetty@Sun.COM MD_CRO_64BIT | options, setno);
8190Sstevel@tonic-gate #endif
8200Sstevel@tonic-gate } else {
8210Sstevel@tonic-gate recid = mddb_createrec((size_t)mgp->size, rec_type, 0,
8227563SPrasad.Singamsetty@Sun.COM MD_CRO_32BIT | options, setno);
8230Sstevel@tonic-gate }
8240Sstevel@tonic-gate if (recid < 0) {
8250Sstevel@tonic-gate rval = mddbstatus2error(mdep, (int)recid, mnum, setno);
8260Sstevel@tonic-gate goto out;
8270Sstevel@tonic-gate }
8280Sstevel@tonic-gate
8290Sstevel@tonic-gate /* get the address of the new unit */
8300Sstevel@tonic-gate new_un = (mp_unit_t *)mddb_getrecaddr(recid);
8310Sstevel@tonic-gate
8320Sstevel@tonic-gate /* copy in the user's unit struct */
8330Sstevel@tonic-gate err = ddi_copyin((void *)(uintptr_t)mgp->mdp, new_un,
8340Sstevel@tonic-gate (size_t)mgp->size, mode);
8350Sstevel@tonic-gate if (err) {
8360Sstevel@tonic-gate mddb_deleterec_wrapper(recid);
8370Sstevel@tonic-gate rval = EFAULT;
8380Sstevel@tonic-gate goto out;
8390Sstevel@tonic-gate }
8401623Stw21770 if (options & MD_CRO_FN)
8411623Stw21770 new_un->c.un_revision |= MD_FN_META_DEV;
8420Sstevel@tonic-gate
8430Sstevel@tonic-gate /* All 64 bit metadevices only support EFI labels. */
8440Sstevel@tonic-gate if (mgp->options & MD_CRO_64BIT) {
8450Sstevel@tonic-gate new_un->c.un_flag |= MD_EFILABEL;
8460Sstevel@tonic-gate /*
8470Sstevel@tonic-gate * If the device was previously smaller than a terabyte,
8480Sstevel@tonic-gate * and had a vtoc record attached to it, we remove the
8490Sstevel@tonic-gate * vtoc record, because the layout has changed completely.
8500Sstevel@tonic-gate */
8511623Stw21770 if (((un->c.un_revision & MD_64BIT_META_DEV) == 0) &&
8520Sstevel@tonic-gate (un->c.un_vtoc_id != 0)) {
8530Sstevel@tonic-gate old_vtoc = un->c.un_vtoc_id;
8540Sstevel@tonic-gate new_un->c.un_vtoc_id =
8557563SPrasad.Singamsetty@Sun.COM md_vtoc_to_efi_record(old_vtoc, setno);
8560Sstevel@tonic-gate }
8570Sstevel@tonic-gate }
8580Sstevel@tonic-gate
8590Sstevel@tonic-gate /* commit new unit struct */
8600Sstevel@tonic-gate MD_RECID(new_un) = recid;
8610Sstevel@tonic-gate mddb_commitrec_wrapper(recid);
8620Sstevel@tonic-gate
8630Sstevel@tonic-gate /*
8640Sstevel@tonic-gate * delete old unit struct.
8650Sstevel@tonic-gate */
8660Sstevel@tonic-gate mddb_deleterec_wrapper(MD_RECID(un));
8677627SChris.Horne@Sun.COM
8687627SChris.Horne@Sun.COM /* place new unit in in-core array */
8697627SChris.Horne@Sun.COM md_nblocks_set(mnum, new_un->c.un_total_blocks);
8700Sstevel@tonic-gate MD_UNIT(mnum) = new_un;
8717627SChris.Horne@Sun.COM
8720Sstevel@tonic-gate SE_NOTIFY(EC_SVM_CONFIG, ESC_SVM_GROW, TAG_METADEVICE,
8730Sstevel@tonic-gate MD_UN2SET(new_un), MD_SID(new_un));
8740Sstevel@tonic-gate
8750Sstevel@tonic-gate /*
8760Sstevel@tonic-gate * If old_vtoc has a non zero value, we know:
8770Sstevel@tonic-gate * - This unit crossed the border from smaller to larger one TB
8780Sstevel@tonic-gate * - There was a vtoc record for the unit,
8790Sstevel@tonic-gate * - This vtoc record is no longer needed, because
8800Sstevel@tonic-gate * a new efi record has been created for this un.
8810Sstevel@tonic-gate */
8820Sstevel@tonic-gate if (old_vtoc != 0) {
8830Sstevel@tonic-gate mddb_deleterec_wrapper(old_vtoc);
8840Sstevel@tonic-gate }
8850Sstevel@tonic-gate
8860Sstevel@tonic-gate /* release locks, return success */
8870Sstevel@tonic-gate out:
8880Sstevel@tonic-gate for (i = npar - 1; (i >= 0); --i)
8890Sstevel@tonic-gate md_ioctl_writerexit(&plock[i]);
8900Sstevel@tonic-gate rw_exit(&md_unit_array_rw.lock);
8910Sstevel@tonic-gate if (plock != NULL)
8920Sstevel@tonic-gate kmem_free(plock, npar * sizeof (*plock));
8930Sstevel@tonic-gate if (par != NULL)
8940Sstevel@tonic-gate kmem_free(par, npar * sizeof (*par));
8950Sstevel@tonic-gate return (rval);
8960Sstevel@tonic-gate }
8970Sstevel@tonic-gate
8980Sstevel@tonic-gate /*
8990Sstevel@tonic-gate * FUNCTION: sp_getdevs()
9000Sstevel@tonic-gate * INPUT: d - data ptr.
9010Sstevel@tonic-gate * mode - pass-through to ddi_copyout.
9020Sstevel@tonic-gate * lockp - lock ptr.
9030Sstevel@tonic-gate * OUTPUT: none.
9040Sstevel@tonic-gate * RETURNS: 0 - success.
9050Sstevel@tonic-gate * non-zero - error.
9060Sstevel@tonic-gate * PURPOSE: Get the device on which the soft partition is built.
9070Sstevel@tonic-gate * This is simply a matter of copying out the md_dev64_t stored
9080Sstevel@tonic-gate * in the soft partition unit structure.
9090Sstevel@tonic-gate */
9100Sstevel@tonic-gate static int
sp_getdevs(void * d,int mode,IOLOCK * lockp)9110Sstevel@tonic-gate sp_getdevs(
9120Sstevel@tonic-gate void *d,
9130Sstevel@tonic-gate int mode,
9140Sstevel@tonic-gate IOLOCK *lockp
9150Sstevel@tonic-gate )
9160Sstevel@tonic-gate {
9170Sstevel@tonic-gate minor_t mnum;
9180Sstevel@tonic-gate mdi_unit_t *ui;
9190Sstevel@tonic-gate mp_unit_t *un;
9200Sstevel@tonic-gate md_error_t *mdep;
9210Sstevel@tonic-gate md_dev64_t *devsp;
9220Sstevel@tonic-gate md_dev64_t unit_dev;
9230Sstevel@tonic-gate md_getdevs_params_t *mgdp = (md_getdevs_params_t *)d;
9240Sstevel@tonic-gate
9250Sstevel@tonic-gate
9260Sstevel@tonic-gate mnum = mgdp->mnum;
9270Sstevel@tonic-gate mdep = &(mgdp->mde);
9280Sstevel@tonic-gate
9290Sstevel@tonic-gate mdclrerror(mdep);
9300Sstevel@tonic-gate
9310Sstevel@tonic-gate /* check set */
9320Sstevel@tonic-gate if ((MD_MIN2SET(mnum) >= md_nsets) || (MD_MIN2UNIT(mnum) >= md_nunits))
9330Sstevel@tonic-gate return (mdmderror(mdep, MDE_INVAL_UNIT, mnum));
9340Sstevel@tonic-gate /* check unit */
9350Sstevel@tonic-gate if ((ui = MDI_UNIT(mnum)) == NULL) {
9360Sstevel@tonic-gate return (mdmderror(mdep, MDE_UNIT_NOT_SETUP, mnum));
9370Sstevel@tonic-gate }
9380Sstevel@tonic-gate /* get unit */
9390Sstevel@tonic-gate un = (mp_unit_t *)md_ioctl_readerlock(lockp, ui);
9400Sstevel@tonic-gate devsp = (md_dev64_t *)(uintptr_t)mgdp->devs;
9410Sstevel@tonic-gate
9420Sstevel@tonic-gate /* only ever 1 device for a soft partition */
9430Sstevel@tonic-gate if (mgdp->cnt != 0) {
9440Sstevel@tonic-gate /* do miniroot->target device translation */
9450Sstevel@tonic-gate unit_dev = un->un_dev;
9460Sstevel@tonic-gate if (md_getmajor(unit_dev) != md_major) {
9470Sstevel@tonic-gate if ((unit_dev = md_xlate_mini_2_targ(unit_dev))
9480Sstevel@tonic-gate == NODEV64)
9490Sstevel@tonic-gate return (ENODEV);
9500Sstevel@tonic-gate }
9510Sstevel@tonic-gate /* copyout dev information */
9520Sstevel@tonic-gate if (ddi_copyout(&unit_dev, devsp, sizeof (*devsp), mode) != 0)
9530Sstevel@tonic-gate return (EFAULT);
9540Sstevel@tonic-gate }
9550Sstevel@tonic-gate mgdp->cnt = 1;
9560Sstevel@tonic-gate
9570Sstevel@tonic-gate return (0);
9580Sstevel@tonic-gate }
9590Sstevel@tonic-gate
9600Sstevel@tonic-gate /*
9610Sstevel@tonic-gate * sp_set_capability:
9620Sstevel@tonic-gate * ------------------
9630Sstevel@tonic-gate * Called to set or clear a capability for a softpart
9640Sstevel@tonic-gate * called by the MD_MN_SET_CAP ioctl.
9650Sstevel@tonic-gate */
9660Sstevel@tonic-gate static int
sp_set_capability(md_mn_setcap_params_t * p,IOLOCK * lockp)9670Sstevel@tonic-gate sp_set_capability(md_mn_setcap_params_t *p, IOLOCK *lockp)
9680Sstevel@tonic-gate {
9690Sstevel@tonic-gate set_t setno;
9700Sstevel@tonic-gate mdi_unit_t *ui;
9710Sstevel@tonic-gate mp_unit_t *un;
9720Sstevel@tonic-gate int err = 0;
9730Sstevel@tonic-gate
9740Sstevel@tonic-gate if ((un = sp_getun(p->mnum, &p->mde)) == NULL)
9750Sstevel@tonic-gate return (EINVAL);
9760Sstevel@tonic-gate
9770Sstevel@tonic-gate /* This function is only valid for a multi-node set */
9780Sstevel@tonic-gate setno = MD_MIN2SET(p->mnum);
9790Sstevel@tonic-gate if (!MD_MNSET_SETNO(setno)) {
9800Sstevel@tonic-gate return (EINVAL);
9810Sstevel@tonic-gate }
9820Sstevel@tonic-gate ui = MDI_UNIT(p->mnum);
9830Sstevel@tonic-gate (void) md_ioctl_readerlock(lockp, ui);
9840Sstevel@tonic-gate
9850Sstevel@tonic-gate if (p->sc_set & DKV_ABR_CAP) {
9860Sstevel@tonic-gate void (*inc_abr_count)();
9870Sstevel@tonic-gate
9880Sstevel@tonic-gate ui->ui_tstate |= MD_ABR_CAP; /* Set ABR capability */
9890Sstevel@tonic-gate /* Increment abr count in underlying metadevice */
9900Sstevel@tonic-gate inc_abr_count = (void(*)())md_get_named_service(un->un_dev,
9910Sstevel@tonic-gate 0, MD_INC_ABR_COUNT, 0);
9920Sstevel@tonic-gate if (inc_abr_count != NULL)
9930Sstevel@tonic-gate (void) (*inc_abr_count)(un->un_dev);
9940Sstevel@tonic-gate } else {
9950Sstevel@tonic-gate void (*dec_abr_count)();
9960Sstevel@tonic-gate
9970Sstevel@tonic-gate ui->ui_tstate &= ~MD_ABR_CAP; /* Clear ABR capability */
9980Sstevel@tonic-gate /* Decrement abr count in underlying metadevice */
9990Sstevel@tonic-gate dec_abr_count = (void(*)())md_get_named_service(un->un_dev,
10000Sstevel@tonic-gate 0, MD_DEC_ABR_COUNT, 0);
10010Sstevel@tonic-gate if (dec_abr_count != NULL)
10020Sstevel@tonic-gate (void) (*dec_abr_count)(un->un_dev);
10030Sstevel@tonic-gate }
10040Sstevel@tonic-gate if (p->sc_set & DKV_DMR_CAP) {
10050Sstevel@tonic-gate ui->ui_tstate |= MD_DMR_CAP; /* Set DMR capability */
10060Sstevel@tonic-gate } else {
10070Sstevel@tonic-gate ui->ui_tstate &= ~MD_DMR_CAP; /* Clear DMR capability */
10080Sstevel@tonic-gate }
10090Sstevel@tonic-gate md_ioctl_readerexit(lockp);
10100Sstevel@tonic-gate return (err);
10110Sstevel@tonic-gate }
10120Sstevel@tonic-gate
10130Sstevel@tonic-gate
10140Sstevel@tonic-gate /*
10150Sstevel@tonic-gate * FUNCTION: sp_admin_ioctl().
10160Sstevel@tonic-gate * INPUT: cmd - ioctl to be handled.
10170Sstevel@tonic-gate * data - data ptr.
10180Sstevel@tonic-gate * mode - pass-through to copyin/copyout routines.
10190Sstevel@tonic-gate * lockp - lock ptr.
10200Sstevel@tonic-gate * OUTPUT: none.
10210Sstevel@tonic-gate * RETURNS: 0 - success.
10220Sstevel@tonic-gate * non-zero - error.
10230Sstevel@tonic-gate * PURPOSE: Handle administrative ioctl's. Essentially a large
10240Sstevel@tonic-gate * switch statement to dispatch the ioctl's to their
10250Sstevel@tonic-gate * handlers. See comment at beginning of file for specifics
10260Sstevel@tonic-gate * on which ioctl's are handled.
10270Sstevel@tonic-gate */
10280Sstevel@tonic-gate static int
sp_admin_ioctl(int cmd,void * data,int mode,IOLOCK * lockp)10290Sstevel@tonic-gate sp_admin_ioctl(int cmd, void *data, int mode, IOLOCK *lockp)
10300Sstevel@tonic-gate {
10310Sstevel@tonic-gate size_t sz = 0;
10320Sstevel@tonic-gate void *d = NULL;
10330Sstevel@tonic-gate int err = 0;
10340Sstevel@tonic-gate
10350Sstevel@tonic-gate /* We can only handle 32-bit clients for internal commands */
10360Sstevel@tonic-gate if ((mode & DATAMODEL_MASK) != DATAMODEL_ILP32) {
10370Sstevel@tonic-gate return (EINVAL);
10380Sstevel@tonic-gate }
10390Sstevel@tonic-gate
10400Sstevel@tonic-gate /* handle ioctl */
10410Sstevel@tonic-gate switch (cmd) {
10420Sstevel@tonic-gate
10430Sstevel@tonic-gate case MD_IOCSET:
10440Sstevel@tonic-gate {
10450Sstevel@tonic-gate /* create new soft partition */
10460Sstevel@tonic-gate if (! (mode & FWRITE))
10470Sstevel@tonic-gate return (EACCES);
10480Sstevel@tonic-gate
10490Sstevel@tonic-gate sz = sizeof (md_set_params_t);
10500Sstevel@tonic-gate
10510Sstevel@tonic-gate d = kmem_alloc(sz, KM_SLEEP);
10520Sstevel@tonic-gate
10530Sstevel@tonic-gate if (ddi_copyin(data, d, sz, mode)) {
10540Sstevel@tonic-gate err = EFAULT;
10550Sstevel@tonic-gate break;
10560Sstevel@tonic-gate }
10570Sstevel@tonic-gate
10580Sstevel@tonic-gate err = sp_set(d, mode);
10590Sstevel@tonic-gate break;
10600Sstevel@tonic-gate }
10610Sstevel@tonic-gate
10620Sstevel@tonic-gate case MD_IOCGET:
10630Sstevel@tonic-gate {
10640Sstevel@tonic-gate /* get soft partition unit structure */
10650Sstevel@tonic-gate if (! (mode & FREAD))
10660Sstevel@tonic-gate return (EACCES);
10670Sstevel@tonic-gate
10680Sstevel@tonic-gate sz = sizeof (md_i_get_t);
10690Sstevel@tonic-gate
10700Sstevel@tonic-gate d = kmem_alloc(sz, KM_SLEEP);
10710Sstevel@tonic-gate
10720Sstevel@tonic-gate if (ddi_copyin(data, d, sz, mode)) {
10730Sstevel@tonic-gate err = EFAULT;
10740Sstevel@tonic-gate break;
10750Sstevel@tonic-gate }
10760Sstevel@tonic-gate
10770Sstevel@tonic-gate err = sp_get(d, mode, lockp);
10780Sstevel@tonic-gate break;
10790Sstevel@tonic-gate }
10800Sstevel@tonic-gate case MD_IOCRESET:
10810Sstevel@tonic-gate {
10820Sstevel@tonic-gate /* delete soft partition */
10830Sstevel@tonic-gate if (! (mode & FWRITE))
10840Sstevel@tonic-gate return (EACCES);
10850Sstevel@tonic-gate
10860Sstevel@tonic-gate sz = sizeof (md_sp_reset_t);
10870Sstevel@tonic-gate d = kmem_alloc(sz, KM_SLEEP);
10880Sstevel@tonic-gate
10890Sstevel@tonic-gate if (ddi_copyin(data, d, sz, mode)) {
10900Sstevel@tonic-gate err = EFAULT;
10910Sstevel@tonic-gate break;
10920Sstevel@tonic-gate }
10930Sstevel@tonic-gate
10940Sstevel@tonic-gate err = sp_reset((md_sp_reset_t *)d);
10950Sstevel@tonic-gate break;
10960Sstevel@tonic-gate }
10970Sstevel@tonic-gate
10980Sstevel@tonic-gate case MD_IOCGROW:
10990Sstevel@tonic-gate {
11000Sstevel@tonic-gate /* grow soft partition */
11010Sstevel@tonic-gate if (! (mode & FWRITE))
11020Sstevel@tonic-gate return (EACCES);
11030Sstevel@tonic-gate
11040Sstevel@tonic-gate sz = sizeof (md_grow_params_t);
11050Sstevel@tonic-gate d = kmem_alloc(sz, KM_SLEEP);
11060Sstevel@tonic-gate
11070Sstevel@tonic-gate if (ddi_copyin(data, d, sz, mode)) {
11080Sstevel@tonic-gate err = EFAULT;
11090Sstevel@tonic-gate break;
11100Sstevel@tonic-gate }
11110Sstevel@tonic-gate
11120Sstevel@tonic-gate err = sp_grow(d, mode, lockp);
11130Sstevel@tonic-gate break;
11140Sstevel@tonic-gate }
11150Sstevel@tonic-gate
11160Sstevel@tonic-gate case MD_IOCGET_DEVS:
11170Sstevel@tonic-gate {
11180Sstevel@tonic-gate /* get underlying device */
11190Sstevel@tonic-gate if (! (mode & FREAD))
11200Sstevel@tonic-gate return (EACCES);
11210Sstevel@tonic-gate
11220Sstevel@tonic-gate sz = sizeof (md_getdevs_params_t);
11230Sstevel@tonic-gate d = kmem_alloc(sz, KM_SLEEP);
11240Sstevel@tonic-gate
11250Sstevel@tonic-gate if (ddi_copyin(data, d, sz, mode)) {
11260Sstevel@tonic-gate err = EFAULT;
11270Sstevel@tonic-gate break;
11280Sstevel@tonic-gate }
11290Sstevel@tonic-gate
11300Sstevel@tonic-gate err = sp_getdevs(d, mode, lockp);
11310Sstevel@tonic-gate break;
11320Sstevel@tonic-gate }
11330Sstevel@tonic-gate
11340Sstevel@tonic-gate case MD_IOC_SPSTATUS:
11350Sstevel@tonic-gate {
11360Sstevel@tonic-gate /* set the status field of one or more soft partitions */
11370Sstevel@tonic-gate if (! (mode & FWRITE))
11380Sstevel@tonic-gate return (EACCES);
11390Sstevel@tonic-gate
11400Sstevel@tonic-gate sz = sizeof (md_sp_statusset_t);
11410Sstevel@tonic-gate d = kmem_alloc(sz, KM_SLEEP);
11420Sstevel@tonic-gate
11430Sstevel@tonic-gate if (ddi_copyin(data, d, sz, mode)) {
11440Sstevel@tonic-gate err = EFAULT;
11450Sstevel@tonic-gate break;
11460Sstevel@tonic-gate }
11470Sstevel@tonic-gate
11480Sstevel@tonic-gate err = sp_setstatus(d, mode, lockp);
11490Sstevel@tonic-gate break;
11500Sstevel@tonic-gate }
11510Sstevel@tonic-gate
11520Sstevel@tonic-gate case MD_IOC_SPUPDATEWM:
11538452SJohn.Wren.Kennedy@Sun.COM case MD_MN_IOC_SPUPDATEWM:
11540Sstevel@tonic-gate {
11550Sstevel@tonic-gate if (! (mode & FWRITE))
11560Sstevel@tonic-gate return (EACCES);
11570Sstevel@tonic-gate
11580Sstevel@tonic-gate sz = sizeof (md_sp_update_wm_t);
11590Sstevel@tonic-gate d = kmem_alloc(sz, KM_SLEEP);
11600Sstevel@tonic-gate
11610Sstevel@tonic-gate if (ddi_copyin(data, d, sz, mode)) {
11620Sstevel@tonic-gate err = EFAULT;
11630Sstevel@tonic-gate break;
11640Sstevel@tonic-gate }
11650Sstevel@tonic-gate
11660Sstevel@tonic-gate err = sp_update_watermarks(d, mode);
11670Sstevel@tonic-gate break;
11680Sstevel@tonic-gate }
11690Sstevel@tonic-gate
11700Sstevel@tonic-gate case MD_IOC_SPREADWM:
11710Sstevel@tonic-gate {
11720Sstevel@tonic-gate if (! (mode & FREAD))
11730Sstevel@tonic-gate return (EACCES);
11740Sstevel@tonic-gate
11750Sstevel@tonic-gate sz = sizeof (md_sp_read_wm_t);
11760Sstevel@tonic-gate d = kmem_alloc(sz, KM_SLEEP);
11770Sstevel@tonic-gate
11780Sstevel@tonic-gate if (ddi_copyin(data, d, sz, mode)) {
11790Sstevel@tonic-gate err = EFAULT;
11800Sstevel@tonic-gate break;
11810Sstevel@tonic-gate }
11820Sstevel@tonic-gate
11830Sstevel@tonic-gate err = sp_read_watermark(d, mode);
11840Sstevel@tonic-gate break;
11850Sstevel@tonic-gate }
11860Sstevel@tonic-gate
11870Sstevel@tonic-gate case MD_MN_SET_CAP:
11880Sstevel@tonic-gate {
11890Sstevel@tonic-gate if (! (mode & FWRITE))
11900Sstevel@tonic-gate return (EACCES);
11910Sstevel@tonic-gate
11920Sstevel@tonic-gate sz = sizeof (md_mn_setcap_params_t);
11930Sstevel@tonic-gate d = kmem_alloc(sz, KM_SLEEP);
11940Sstevel@tonic-gate
11950Sstevel@tonic-gate if (ddi_copyin(data, d, sz, mode)) {
11960Sstevel@tonic-gate err = EFAULT;
11970Sstevel@tonic-gate break;
11980Sstevel@tonic-gate }
11990Sstevel@tonic-gate
12000Sstevel@tonic-gate err = sp_set_capability((md_mn_setcap_params_t *)d, lockp);
12010Sstevel@tonic-gate break;
12020Sstevel@tonic-gate }
12030Sstevel@tonic-gate
12040Sstevel@tonic-gate default:
12050Sstevel@tonic-gate return (ENOTTY);
12060Sstevel@tonic-gate }
12070Sstevel@tonic-gate
12080Sstevel@tonic-gate /*
12090Sstevel@tonic-gate * copyout and free any args
12100Sstevel@tonic-gate */
12110Sstevel@tonic-gate if (sz != 0) {
12120Sstevel@tonic-gate if (err == 0) {
12130Sstevel@tonic-gate if (ddi_copyout(d, data, sz, mode) != 0) {
12140Sstevel@tonic-gate err = EFAULT;
12150Sstevel@tonic-gate }
12160Sstevel@tonic-gate }
12170Sstevel@tonic-gate kmem_free(d, sz);
12180Sstevel@tonic-gate }
12190Sstevel@tonic-gate return (err);
12200Sstevel@tonic-gate }
12210Sstevel@tonic-gate
12220Sstevel@tonic-gate
12230Sstevel@tonic-gate /*
12240Sstevel@tonic-gate * FUNCTION: md_sp_ioctl()
12250Sstevel@tonic-gate * INPUT: dev - device we are operating on.
12260Sstevel@tonic-gate * cmd - ioctl to be handled.
12270Sstevel@tonic-gate * data - data ptr.
12280Sstevel@tonic-gate * mode - pass-through to copyin/copyout routines.
12290Sstevel@tonic-gate * lockp - lock ptr.
12300Sstevel@tonic-gate * OUTPUT: none.
12310Sstevel@tonic-gate * RETURNS: 0 - success.
12320Sstevel@tonic-gate * non-zero - error.
12330Sstevel@tonic-gate * PURPOSE: Dispatch ioctl's. Administrative ioctl's are handled
12340Sstevel@tonic-gate * by sp_admin_ioctl. All others (see comment at beginning
12350Sstevel@tonic-gate * of this file) are handled in-line here.
12360Sstevel@tonic-gate */
12370Sstevel@tonic-gate int
md_sp_ioctl(dev_t dev,int cmd,void * data,int mode,IOLOCK * lockp)12380Sstevel@tonic-gate md_sp_ioctl(dev_t dev, int cmd, void *data, int mode, IOLOCK *lockp)
12390Sstevel@tonic-gate {
12400Sstevel@tonic-gate minor_t mnum = getminor(dev);
12410Sstevel@tonic-gate mp_unit_t *un;
12420Sstevel@tonic-gate mdi_unit_t *ui;
12430Sstevel@tonic-gate int err = 0;
12440Sstevel@tonic-gate
12450Sstevel@tonic-gate /* handle admin ioctls */
12460Sstevel@tonic-gate if (mnum == MD_ADM_MINOR)
12470Sstevel@tonic-gate return (sp_admin_ioctl(cmd, data, mode, lockp));
12480Sstevel@tonic-gate
12490Sstevel@tonic-gate /* check unit */
12500Sstevel@tonic-gate if ((MD_MIN2SET(mnum) >= md_nsets) ||
12510Sstevel@tonic-gate (MD_MIN2UNIT(mnum) >= md_nunits) ||
12520Sstevel@tonic-gate ((ui = MDI_UNIT(mnum)) == NULL) ||
12530Sstevel@tonic-gate ((un = MD_UNIT(mnum)) == NULL))
12540Sstevel@tonic-gate return (ENXIO);
12550Sstevel@tonic-gate
12560Sstevel@tonic-gate /* is this a supported ioctl? */
12577563SPrasad.Singamsetty@Sun.COM err = md_check_ioctl_against_unit(cmd, un->c);
12580Sstevel@tonic-gate if (err != 0) {
12590Sstevel@tonic-gate return (err);
12600Sstevel@tonic-gate }
12610Sstevel@tonic-gate
12620Sstevel@tonic-gate
12630Sstevel@tonic-gate /* handle ioctl */
12640Sstevel@tonic-gate switch (cmd) {
12650Sstevel@tonic-gate
12660Sstevel@tonic-gate case DKIOCINFO:
12670Sstevel@tonic-gate {
12680Sstevel@tonic-gate /* "disk" info */
12690Sstevel@tonic-gate struct dk_cinfo *p;
12700Sstevel@tonic-gate
12710Sstevel@tonic-gate if (! (mode & FREAD))
12720Sstevel@tonic-gate return (EACCES);
12730Sstevel@tonic-gate
12740Sstevel@tonic-gate p = kmem_alloc(sizeof (*p), KM_SLEEP);
12750Sstevel@tonic-gate
12760Sstevel@tonic-gate get_info(p, mnum);
12770Sstevel@tonic-gate if (ddi_copyout((caddr_t)p, data, sizeof (*p), mode) != 0)
12780Sstevel@tonic-gate err = EFAULT;
12790Sstevel@tonic-gate
12800Sstevel@tonic-gate kmem_free(p, sizeof (*p));
12810Sstevel@tonic-gate return (err);
12820Sstevel@tonic-gate }
12830Sstevel@tonic-gate
12840Sstevel@tonic-gate case DKIOCGMEDIAINFO:
12850Sstevel@tonic-gate {
12860Sstevel@tonic-gate struct dk_minfo p;
12870Sstevel@tonic-gate
12880Sstevel@tonic-gate if (! (mode & FREAD))
12890Sstevel@tonic-gate return (EACCES);
12900Sstevel@tonic-gate
12910Sstevel@tonic-gate get_minfo(&p, mnum);
12920Sstevel@tonic-gate if (ddi_copyout(&p, data, sizeof (struct dk_minfo), mode) != 0)
12930Sstevel@tonic-gate err = EFAULT;
12940Sstevel@tonic-gate
12950Sstevel@tonic-gate return (err);
12960Sstevel@tonic-gate }
12970Sstevel@tonic-gate
12980Sstevel@tonic-gate case DKIOCGGEOM:
12990Sstevel@tonic-gate {
13000Sstevel@tonic-gate /* geometry information */
13010Sstevel@tonic-gate struct dk_geom *p;
13020Sstevel@tonic-gate
13030Sstevel@tonic-gate if (! (mode & FREAD))
13040Sstevel@tonic-gate return (EACCES);
13050Sstevel@tonic-gate
13060Sstevel@tonic-gate p = kmem_alloc(sizeof (*p), KM_SLEEP);
13070Sstevel@tonic-gate
13080Sstevel@tonic-gate md_get_geom((md_unit_t *)un, p);
13090Sstevel@tonic-gate if (ddi_copyout((caddr_t)p, data, sizeof (*p),
13100Sstevel@tonic-gate mode) != 0)
13110Sstevel@tonic-gate err = EFAULT;
13120Sstevel@tonic-gate
13130Sstevel@tonic-gate kmem_free(p, sizeof (*p));
13140Sstevel@tonic-gate return (err);
13150Sstevel@tonic-gate }
13160Sstevel@tonic-gate case DKIOCGAPART:
13170Sstevel@tonic-gate {
13180Sstevel@tonic-gate struct dk_map dmp;
13190Sstevel@tonic-gate
13200Sstevel@tonic-gate err = 0;
13210Sstevel@tonic-gate md_get_cgapart((md_unit_t *)un, &dmp);
13220Sstevel@tonic-gate
13230Sstevel@tonic-gate if ((mode & DATAMODEL_MASK) == DATAMODEL_NATIVE) {
13240Sstevel@tonic-gate if (ddi_copyout((caddr_t)&dmp, data, sizeof (dmp),
13257563SPrasad.Singamsetty@Sun.COM mode) != 0)
13260Sstevel@tonic-gate err = EFAULT;
13270Sstevel@tonic-gate }
13280Sstevel@tonic-gate #ifdef _SYSCALL32
13290Sstevel@tonic-gate else {
13300Sstevel@tonic-gate struct dk_map32 dmp32;
13310Sstevel@tonic-gate
13320Sstevel@tonic-gate dmp32.dkl_cylno = dmp.dkl_cylno;
13330Sstevel@tonic-gate dmp32.dkl_nblk = dmp.dkl_nblk;
13340Sstevel@tonic-gate
13350Sstevel@tonic-gate if (ddi_copyout((caddr_t)&dmp32, data, sizeof (dmp32),
13367563SPrasad.Singamsetty@Sun.COM mode) != 0)
13370Sstevel@tonic-gate err = EFAULT;
13380Sstevel@tonic-gate }
13390Sstevel@tonic-gate #endif /* _SYSCALL32 */
13400Sstevel@tonic-gate
13410Sstevel@tonic-gate return (err);
13420Sstevel@tonic-gate }
13430Sstevel@tonic-gate case DKIOCGVTOC:
13440Sstevel@tonic-gate {
13450Sstevel@tonic-gate /* vtoc information */
1346*9017SJohn.Wren.Kennedy@Sun.COM struct vtoc *vtoc;
13470Sstevel@tonic-gate
13480Sstevel@tonic-gate if (! (mode & FREAD))
13490Sstevel@tonic-gate return (EACCES);
13500Sstevel@tonic-gate
1351*9017SJohn.Wren.Kennedy@Sun.COM vtoc = kmem_zalloc(sizeof (*vtoc), KM_SLEEP);
1352*9017SJohn.Wren.Kennedy@Sun.COM md_get_vtoc((md_unit_t *)un, vtoc);
13530Sstevel@tonic-gate
13540Sstevel@tonic-gate if ((mode & DATAMODEL_MASK) == DATAMODEL_NATIVE) {
1355*9017SJohn.Wren.Kennedy@Sun.COM if (ddi_copyout(vtoc, data, sizeof (*vtoc), mode))
13560Sstevel@tonic-gate err = EFAULT;
13570Sstevel@tonic-gate }
13580Sstevel@tonic-gate #ifdef _SYSCALL32
13590Sstevel@tonic-gate else {
1360*9017SJohn.Wren.Kennedy@Sun.COM struct vtoc32 *vtoc32;
1361*9017SJohn.Wren.Kennedy@Sun.COM
1362*9017SJohn.Wren.Kennedy@Sun.COM vtoc32 = kmem_zalloc(sizeof (*vtoc32), KM_SLEEP);
1363*9017SJohn.Wren.Kennedy@Sun.COM
1364*9017SJohn.Wren.Kennedy@Sun.COM vtoctovtoc32((*vtoc), (*vtoc32));
1365*9017SJohn.Wren.Kennedy@Sun.COM if (ddi_copyout(vtoc32, data, sizeof (*vtoc32), mode))
13660Sstevel@tonic-gate err = EFAULT;
1367*9017SJohn.Wren.Kennedy@Sun.COM kmem_free(vtoc32, sizeof (*vtoc32));
13680Sstevel@tonic-gate }
13690Sstevel@tonic-gate #endif /* _SYSCALL32 */
13700Sstevel@tonic-gate
1371*9017SJohn.Wren.Kennedy@Sun.COM kmem_free(vtoc, sizeof (*vtoc));
13720Sstevel@tonic-gate return (err);
13730Sstevel@tonic-gate }
13740Sstevel@tonic-gate
13750Sstevel@tonic-gate case DKIOCSVTOC:
13760Sstevel@tonic-gate {
1377*9017SJohn.Wren.Kennedy@Sun.COM struct vtoc *vtoc;
13780Sstevel@tonic-gate
13790Sstevel@tonic-gate if (! (mode & FWRITE))
13800Sstevel@tonic-gate return (EACCES);
13810Sstevel@tonic-gate
1382*9017SJohn.Wren.Kennedy@Sun.COM vtoc = kmem_zalloc(sizeof (*vtoc), KM_SLEEP);
13830Sstevel@tonic-gate if ((mode & DATAMODEL_MASK) == DATAMODEL_NATIVE) {
1384*9017SJohn.Wren.Kennedy@Sun.COM if (ddi_copyin(data, vtoc, sizeof (*vtoc), mode)) {
13850Sstevel@tonic-gate err = EFAULT;
13860Sstevel@tonic-gate }
13870Sstevel@tonic-gate }
13880Sstevel@tonic-gate #ifdef _SYSCALL32
13890Sstevel@tonic-gate else {
1390*9017SJohn.Wren.Kennedy@Sun.COM struct vtoc32 *vtoc32;
1391*9017SJohn.Wren.Kennedy@Sun.COM
1392*9017SJohn.Wren.Kennedy@Sun.COM vtoc32 = kmem_zalloc(sizeof (*vtoc32), KM_SLEEP);
1393*9017SJohn.Wren.Kennedy@Sun.COM
1394*9017SJohn.Wren.Kennedy@Sun.COM if (ddi_copyin(data, vtoc32, sizeof (*vtoc32), mode)) {
13950Sstevel@tonic-gate err = EFAULT;
13960Sstevel@tonic-gate } else {
1397*9017SJohn.Wren.Kennedy@Sun.COM vtoc32tovtoc((*vtoc32), (*vtoc));
13980Sstevel@tonic-gate }
1399*9017SJohn.Wren.Kennedy@Sun.COM kmem_free(vtoc32, sizeof (*vtoc32));
14000Sstevel@tonic-gate }
14010Sstevel@tonic-gate #endif /* _SYSCALL32 */
14020Sstevel@tonic-gate
14030Sstevel@tonic-gate if (err == 0)
1404*9017SJohn.Wren.Kennedy@Sun.COM err = md_set_vtoc((md_unit_t *)un, vtoc);
14050Sstevel@tonic-gate
1406*9017SJohn.Wren.Kennedy@Sun.COM kmem_free(vtoc, sizeof (*vtoc));
14070Sstevel@tonic-gate return (err);
14080Sstevel@tonic-gate }
14090Sstevel@tonic-gate
14107563SPrasad.Singamsetty@Sun.COM case DKIOCGEXTVTOC:
14117563SPrasad.Singamsetty@Sun.COM {
14127563SPrasad.Singamsetty@Sun.COM /* extended vtoc information */
1413*9017SJohn.Wren.Kennedy@Sun.COM struct extvtoc *extvtoc;
14147563SPrasad.Singamsetty@Sun.COM
14157563SPrasad.Singamsetty@Sun.COM if (! (mode & FREAD))
14167563SPrasad.Singamsetty@Sun.COM return (EACCES);
14177563SPrasad.Singamsetty@Sun.COM
1418*9017SJohn.Wren.Kennedy@Sun.COM extvtoc = kmem_zalloc(sizeof (*extvtoc), KM_SLEEP);
1419*9017SJohn.Wren.Kennedy@Sun.COM md_get_extvtoc((md_unit_t *)un, extvtoc);
14207563SPrasad.Singamsetty@Sun.COM
1421*9017SJohn.Wren.Kennedy@Sun.COM if (ddi_copyout(extvtoc, data, sizeof (*extvtoc), mode))
14227563SPrasad.Singamsetty@Sun.COM err = EFAULT;
14237563SPrasad.Singamsetty@Sun.COM
1424*9017SJohn.Wren.Kennedy@Sun.COM kmem_free(extvtoc, sizeof (*extvtoc));
14257563SPrasad.Singamsetty@Sun.COM return (err);
14267563SPrasad.Singamsetty@Sun.COM }
14277563SPrasad.Singamsetty@Sun.COM
14287563SPrasad.Singamsetty@Sun.COM case DKIOCSEXTVTOC:
14297563SPrasad.Singamsetty@Sun.COM {
1430*9017SJohn.Wren.Kennedy@Sun.COM struct extvtoc *extvtoc;
14317563SPrasad.Singamsetty@Sun.COM
14327563SPrasad.Singamsetty@Sun.COM if (! (mode & FWRITE))
14337563SPrasad.Singamsetty@Sun.COM return (EACCES);
14347563SPrasad.Singamsetty@Sun.COM
1435*9017SJohn.Wren.Kennedy@Sun.COM extvtoc = kmem_zalloc(sizeof (*extvtoc), KM_SLEEP);
1436*9017SJohn.Wren.Kennedy@Sun.COM if (ddi_copyin(data, extvtoc, sizeof (*extvtoc), mode)) {
14377563SPrasad.Singamsetty@Sun.COM err = EFAULT;
14387563SPrasad.Singamsetty@Sun.COM }
14397563SPrasad.Singamsetty@Sun.COM
14407563SPrasad.Singamsetty@Sun.COM if (err == 0)
1441*9017SJohn.Wren.Kennedy@Sun.COM err = md_set_extvtoc((md_unit_t *)un, extvtoc);
14427563SPrasad.Singamsetty@Sun.COM
1443*9017SJohn.Wren.Kennedy@Sun.COM kmem_free(extvtoc, sizeof (*extvtoc));
14447563SPrasad.Singamsetty@Sun.COM return (err);
14457563SPrasad.Singamsetty@Sun.COM }
14467563SPrasad.Singamsetty@Sun.COM
14470Sstevel@tonic-gate case DKIOCGETEFI:
14480Sstevel@tonic-gate {
14490Sstevel@tonic-gate /*
14500Sstevel@tonic-gate * This one can be done centralized,
14510Sstevel@tonic-gate * no need to put in the same code for all types of metadevices
14520Sstevel@tonic-gate */
14530Sstevel@tonic-gate return (md_dkiocgetefi(mnum, data, mode));
14540Sstevel@tonic-gate }
14550Sstevel@tonic-gate case DKIOCSETEFI:
14560Sstevel@tonic-gate {
14570Sstevel@tonic-gate /*
14580Sstevel@tonic-gate * This one can be done centralized,
14590Sstevel@tonic-gate * no need to put in the same code for all types of metadevices
14600Sstevel@tonic-gate */
14610Sstevel@tonic-gate return (md_dkiocsetefi(mnum, data, mode));
14620Sstevel@tonic-gate }
14630Sstevel@tonic-gate
14640Sstevel@tonic-gate case DKIOCPARTITION:
14650Sstevel@tonic-gate {
14660Sstevel@tonic-gate return (md_dkiocpartition(mnum, data, mode));
14670Sstevel@tonic-gate }
14680Sstevel@tonic-gate
14690Sstevel@tonic-gate case DKIOCGETVOLCAP:
14700Sstevel@tonic-gate {
14710Sstevel@tonic-gate /*
14720Sstevel@tonic-gate * Return the supported capabilities for the soft-partition.
14730Sstevel@tonic-gate * We can only support those caps that are provided by the
14740Sstevel@tonic-gate * underlying device.
14750Sstevel@tonic-gate */
14760Sstevel@tonic-gate
14770Sstevel@tonic-gate volcap_t vc;
14780Sstevel@tonic-gate
14790Sstevel@tonic-gate if (!MD_MNSET_SETNO(MD_MIN2SET(mnum)))
14800Sstevel@tonic-gate return (EINVAL);
14810Sstevel@tonic-gate
14820Sstevel@tonic-gate if (! (mode & FREAD))
14830Sstevel@tonic-gate return (EACCES);
14840Sstevel@tonic-gate
14850Sstevel@tonic-gate bzero(&vc, sizeof (vc));
14860Sstevel@tonic-gate
14870Sstevel@tonic-gate /* Send ioctl to underlying driver */
14880Sstevel@tonic-gate
14890Sstevel@tonic-gate err = md_call_ioctl(un->un_dev, cmd, &vc, (mode | FKIOCTL),
14900Sstevel@tonic-gate lockp);
14910Sstevel@tonic-gate
14920Sstevel@tonic-gate if (err == 0)
14930Sstevel@tonic-gate ui->ui_capab = vc.vc_info;
14940Sstevel@tonic-gate
14950Sstevel@tonic-gate if (ddi_copyout(&vc, data, sizeof (vc), mode))
14960Sstevel@tonic-gate err = EFAULT;
14970Sstevel@tonic-gate
14980Sstevel@tonic-gate return (err);
14990Sstevel@tonic-gate }
15000Sstevel@tonic-gate
15010Sstevel@tonic-gate case DKIOCSETVOLCAP:
15020Sstevel@tonic-gate {
15030Sstevel@tonic-gate /*
15040Sstevel@tonic-gate * Enable a supported capability (as returned by DKIOCGETVOLCAP)
15050Sstevel@tonic-gate * Do not pass the request down as we're the top-level device
15060Sstevel@tonic-gate * handler for the application.
15070Sstevel@tonic-gate * If the requested capability is supported (set in ui_capab),
15080Sstevel@tonic-gate * set the corresponding bit in ui_tstate so that we can pass
15090Sstevel@tonic-gate * the appropriate flag when performing i/o.
15100Sstevel@tonic-gate * This request is propagated to all nodes.
15110Sstevel@tonic-gate */
15120Sstevel@tonic-gate volcap_t vc, vc1;
15130Sstevel@tonic-gate volcapset_t volcap = 0;
15140Sstevel@tonic-gate void (*check_offline)();
15150Sstevel@tonic-gate int offline_status = 0;
15160Sstevel@tonic-gate
15170Sstevel@tonic-gate if (!MD_MNSET_SETNO(MD_MIN2SET(mnum)))
15180Sstevel@tonic-gate return (EINVAL);
15190Sstevel@tonic-gate
15200Sstevel@tonic-gate if (! (mode & FWRITE))
15210Sstevel@tonic-gate return (EACCES);
15220Sstevel@tonic-gate
15230Sstevel@tonic-gate if (ddi_copyin(data, &vc, sizeof (vc), mode))
15240Sstevel@tonic-gate return (EFAULT);
15250Sstevel@tonic-gate
15260Sstevel@tonic-gate /*
15270Sstevel@tonic-gate * Send DKIOCGETVOLCAP to underlying driver to see if
15280Sstevel@tonic-gate * capability supported
15290Sstevel@tonic-gate */
15300Sstevel@tonic-gate
15310Sstevel@tonic-gate vc1.vc_info = 0;
15320Sstevel@tonic-gate err = md_call_ioctl(un->un_dev, DKIOCGETVOLCAP, &vc1,
15330Sstevel@tonic-gate (mode | FKIOCTL), lockp);
15340Sstevel@tonic-gate if (err != 0)
15350Sstevel@tonic-gate return (err);
15360Sstevel@tonic-gate
15370Sstevel@tonic-gate /* Save capabilities */
15380Sstevel@tonic-gate ui->ui_capab = vc1.vc_info;
15390Sstevel@tonic-gate /*
15400Sstevel@tonic-gate * Error if required capability not supported by underlying
15410Sstevel@tonic-gate * driver
15420Sstevel@tonic-gate */
15430Sstevel@tonic-gate if ((vc1.vc_info & vc.vc_set) == 0)
15440Sstevel@tonic-gate return (ENOTSUP);
15450Sstevel@tonic-gate
15460Sstevel@tonic-gate
15470Sstevel@tonic-gate /*
15480Sstevel@tonic-gate * Check if underlying mirror has an offline submirror,
15490Sstevel@tonic-gate * fail if there is on offline submirror
15500Sstevel@tonic-gate */
15510Sstevel@tonic-gate check_offline = (void(*)())md_get_named_service(un->un_dev,
15520Sstevel@tonic-gate 0, MD_CHECK_OFFLINE, 0);
15530Sstevel@tonic-gate if (check_offline != NULL)
15540Sstevel@tonic-gate (void) (*check_offline)(un->un_dev, &offline_status);
15550Sstevel@tonic-gate if (offline_status)
15560Sstevel@tonic-gate return (EINVAL);
15570Sstevel@tonic-gate
15580Sstevel@tonic-gate if (ui->ui_tstate & MD_ABR_CAP)
15590Sstevel@tonic-gate volcap |= DKV_ABR_CAP;
15600Sstevel@tonic-gate
15610Sstevel@tonic-gate /* Only send capability message if there is a change */
15620Sstevel@tonic-gate if ((vc.vc_set & (DKV_ABR_CAP)) != volcap)
15630Sstevel@tonic-gate err = mdmn_send_capability_message(mnum, vc, lockp);
15640Sstevel@tonic-gate return (err);
15650Sstevel@tonic-gate }
15660Sstevel@tonic-gate
15670Sstevel@tonic-gate case DKIOCDMR:
15680Sstevel@tonic-gate {
15690Sstevel@tonic-gate /*
15700Sstevel@tonic-gate * Only valid for MN sets. We need to pass it down to the
15710Sstevel@tonic-gate * underlying driver if its a metadevice, after we've modified
15720Sstevel@tonic-gate * the offsets to pick up the correct lower-level device
15730Sstevel@tonic-gate * position.
15740Sstevel@tonic-gate */
15750Sstevel@tonic-gate vol_directed_rd_t *vdr;
15760Sstevel@tonic-gate #ifdef _MULTI_DATAMODEL
15770Sstevel@tonic-gate vol_directed_rd32_t *vdr32;
15780Sstevel@tonic-gate #endif /* _MULTI_DATAMODEL */
15790Sstevel@tonic-gate
15800Sstevel@tonic-gate if (!MD_MNSET_SETNO(MD_MIN2SET(mnum)))
15810Sstevel@tonic-gate return (EINVAL);
15820Sstevel@tonic-gate
15830Sstevel@tonic-gate if (! (ui->ui_capab & DKV_DMR_CAP))
15840Sstevel@tonic-gate return (EINVAL);
15850Sstevel@tonic-gate
15860Sstevel@tonic-gate vdr = kmem_zalloc(sizeof (vol_directed_rd_t), KM_NOSLEEP);
15870Sstevel@tonic-gate if (vdr == NULL)
15880Sstevel@tonic-gate return (ENOMEM);
15890Sstevel@tonic-gate
15900Sstevel@tonic-gate /*
15910Sstevel@tonic-gate * Underlying device supports directed mirror read, so update
15920Sstevel@tonic-gate * the user-supplied offset to pick the correct block from the
15930Sstevel@tonic-gate * partitioned metadevice.
15940Sstevel@tonic-gate */
15950Sstevel@tonic-gate #ifdef _MULTI_DATAMODEL
15960Sstevel@tonic-gate vdr32 = kmem_zalloc(sizeof (vol_directed_rd32_t), KM_NOSLEEP);
15970Sstevel@tonic-gate if (vdr32 == NULL) {
15980Sstevel@tonic-gate kmem_free(vdr, sizeof (vol_directed_rd_t));
15990Sstevel@tonic-gate return (ENOMEM);
16000Sstevel@tonic-gate }
16010Sstevel@tonic-gate
16020Sstevel@tonic-gate switch (ddi_model_convert_from(mode & FMODELS)) {
16030Sstevel@tonic-gate case DDI_MODEL_ILP32:
16040Sstevel@tonic-gate if (ddi_copyin(data, vdr32, sizeof (*vdr32), mode)) {
16050Sstevel@tonic-gate kmem_free(vdr, sizeof (*vdr));
16060Sstevel@tonic-gate return (EFAULT);
16070Sstevel@tonic-gate }
16080Sstevel@tonic-gate vdr->vdr_flags = vdr32->vdr_flags;
16090Sstevel@tonic-gate vdr->vdr_offset = vdr32->vdr_offset;
16100Sstevel@tonic-gate vdr->vdr_nbytes = vdr32->vdr_nbytes;
16110Sstevel@tonic-gate vdr->vdr_data = (void *)(uintptr_t)vdr32->vdr_data;
16120Sstevel@tonic-gate vdr->vdr_side = vdr32->vdr_side;
16130Sstevel@tonic-gate break;
16140Sstevel@tonic-gate
16150Sstevel@tonic-gate case DDI_MODEL_NONE:
16160Sstevel@tonic-gate if (ddi_copyin(data, vdr, sizeof (*vdr), mode)) {
16170Sstevel@tonic-gate kmem_free(vdr32, sizeof (*vdr32));
16180Sstevel@tonic-gate kmem_free(vdr, sizeof (*vdr));
16190Sstevel@tonic-gate return (EFAULT);
16200Sstevel@tonic-gate }
16210Sstevel@tonic-gate break;
16220Sstevel@tonic-gate
16230Sstevel@tonic-gate default:
16240Sstevel@tonic-gate kmem_free(vdr32, sizeof (*vdr32));
16250Sstevel@tonic-gate kmem_free(vdr, sizeof (*vdr));
16260Sstevel@tonic-gate return (EFAULT);
16270Sstevel@tonic-gate }
16280Sstevel@tonic-gate #else /* ! _MULTI_DATAMODEL */
16290Sstevel@tonic-gate if (ddi_copyin(data, vdr, sizeof (*vdr), mode)) {
16300Sstevel@tonic-gate kmem_free(vdr, sizeof (*vdr));
16310Sstevel@tonic-gate return (EFAULT);
16320Sstevel@tonic-gate }
16330Sstevel@tonic-gate #endif /* _MULTI_DATA_MODEL */
16340Sstevel@tonic-gate
16350Sstevel@tonic-gate err = sp_directed_read(mnum, vdr, mode);
16360Sstevel@tonic-gate
16370Sstevel@tonic-gate
16380Sstevel@tonic-gate #ifdef _MULTI_DATAMODEL
16390Sstevel@tonic-gate switch (ddi_model_convert_from(mode & FMODELS)) {
16400Sstevel@tonic-gate case DDI_MODEL_ILP32:
16410Sstevel@tonic-gate vdr32->vdr_flags = vdr->vdr_flags;
16420Sstevel@tonic-gate vdr32->vdr_offset = vdr->vdr_offset;
16430Sstevel@tonic-gate vdr32->vdr_side = vdr->vdr_side;
16440Sstevel@tonic-gate vdr32->vdr_bytesread = vdr->vdr_bytesread;
16450Sstevel@tonic-gate bcopy(vdr->vdr_side_name, vdr32->vdr_side_name,
16460Sstevel@tonic-gate sizeof (vdr32->vdr_side_name));
16470Sstevel@tonic-gate
16480Sstevel@tonic-gate if (ddi_copyout(vdr32, data, sizeof (*vdr32), mode))
16490Sstevel@tonic-gate err = EFAULT;
16500Sstevel@tonic-gate break;
16510Sstevel@tonic-gate
16520Sstevel@tonic-gate case DDI_MODEL_NONE:
16530Sstevel@tonic-gate if (ddi_copyout(&vdr, data, sizeof (vdr), mode))
16540Sstevel@tonic-gate err = EFAULT;
16550Sstevel@tonic-gate break;
16560Sstevel@tonic-gate }
16570Sstevel@tonic-gate #else /* ! _MULTI_DATA_MODEL */
16580Sstevel@tonic-gate if (ddi_copyout(&vdr, data, sizeof (vdr), mode))
16590Sstevel@tonic-gate err = EFAULT;
16600Sstevel@tonic-gate #endif /* _MULTI_DATA_MODEL */
16610Sstevel@tonic-gate
16620Sstevel@tonic-gate #ifdef _MULTI_DATAMODEL
16630Sstevel@tonic-gate kmem_free(vdr32, sizeof (*vdr32));
16640Sstevel@tonic-gate #endif /* _MULTI_DATAMODEL */
16650Sstevel@tonic-gate kmem_free(vdr, sizeof (*vdr));
16660Sstevel@tonic-gate
16670Sstevel@tonic-gate return (err);
16680Sstevel@tonic-gate }
16690Sstevel@tonic-gate
16700Sstevel@tonic-gate }
16710Sstevel@tonic-gate
16720Sstevel@tonic-gate /* Option not handled */
16730Sstevel@tonic-gate return (ENOTTY);
16740Sstevel@tonic-gate }
1675