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
5*7656SSherry.Moore@Sun.COM * Common Development and Distribution License (the "License").
6*7656SSherry.Moore@Sun.COM * 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 */
210Sstevel@tonic-gate /*
22*7656SSherry.Moore@Sun.COM * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
230Sstevel@tonic-gate * Use is subject to license terms.
240Sstevel@tonic-gate */
250Sstevel@tonic-gate
260Sstevel@tonic-gate
270Sstevel@tonic-gate #include <sys/types.h>
280Sstevel@tonic-gate #include <sys/file.h>
290Sstevel@tonic-gate #include <sys/errno.h>
300Sstevel@tonic-gate #include <sys/open.h>
310Sstevel@tonic-gate #include <sys/cred.h>
320Sstevel@tonic-gate #include <sys/conf.h>
330Sstevel@tonic-gate #include <sys/modctl.h>
340Sstevel@tonic-gate #include <sys/stat.h>
350Sstevel@tonic-gate #include <sys/ddi.h>
360Sstevel@tonic-gate #include <sys/sunddi.h>
370Sstevel@tonic-gate #include <sys/policy.h>
380Sstevel@tonic-gate #include <sys/pool.h>
390Sstevel@tonic-gate #include <sys/pool_impl.h>
400Sstevel@tonic-gate
410Sstevel@tonic-gate /*
420Sstevel@tonic-gate * The kernel pools subsystem is accessed and manipulated through the pool
430Sstevel@tonic-gate * device, which has two minor nodes /dev/pool, and /dev/poolctl. User
440Sstevel@tonic-gate * processes can comminicate with pools through ioctls on these devices.
450Sstevel@tonic-gate *
460Sstevel@tonic-gate * The poolctl device (POOL_CTL_PARENT) can be used to modify and take
470Sstevel@tonic-gate * snapshot of the current configuration. Only one process on the system
480Sstevel@tonic-gate * can have it open at any given time. This device is also used to enable
490Sstevel@tonic-gate * or disable pools. If pools are disabled, the pool driver can be unloaded
500Sstevel@tonic-gate * and completely removed from the system.
510Sstevel@tonic-gate *
520Sstevel@tonic-gate * The pool "info" device (POOL_INFO_PARENT) can only be used to obtain
530Sstevel@tonic-gate * snapshots of the current configuration and change/query pool bindings.
540Sstevel@tonic-gate * While some reconfiguration transaction via the poolctl device is in
550Sstevel@tonic-gate * progress, all processes using this "info" device will be provided with
560Sstevel@tonic-gate * the snapshot taken at the beginning of that transaction.
570Sstevel@tonic-gate */
580Sstevel@tonic-gate
590Sstevel@tonic-gate #define POOL_CTL_PARENT 0
600Sstevel@tonic-gate #define POOL_INFO_PARENT 1
610Sstevel@tonic-gate
620Sstevel@tonic-gate static dev_info_t *pool_devi; /* pool device information */
630Sstevel@tonic-gate static int pool_openctl; /* poolctl device is already open */
640Sstevel@tonic-gate
650Sstevel@tonic-gate /*ARGSUSED*/
660Sstevel@tonic-gate static int
pool_info(dev_info_t * dip,ddi_info_cmd_t infocmd,void * arg,void ** result)670Sstevel@tonic-gate pool_info(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg, void **result)
680Sstevel@tonic-gate {
690Sstevel@tonic-gate int error = DDI_FAILURE;
700Sstevel@tonic-gate
710Sstevel@tonic-gate switch (infocmd) {
720Sstevel@tonic-gate case DDI_INFO_DEVT2DEVINFO:
730Sstevel@tonic-gate *result = pool_devi;
740Sstevel@tonic-gate error = DDI_SUCCESS;
750Sstevel@tonic-gate break;
760Sstevel@tonic-gate case DDI_INFO_DEVT2INSTANCE:
770Sstevel@tonic-gate /*
780Sstevel@tonic-gate * All dev_t's map to the same, single instance.
790Sstevel@tonic-gate */
800Sstevel@tonic-gate *result = NULL;
810Sstevel@tonic-gate error = DDI_SUCCESS;
820Sstevel@tonic-gate break;
830Sstevel@tonic-gate default:
840Sstevel@tonic-gate break;
850Sstevel@tonic-gate }
860Sstevel@tonic-gate return (error);
870Sstevel@tonic-gate }
880Sstevel@tonic-gate
890Sstevel@tonic-gate static int
pool_detach(dev_info_t * devi,ddi_detach_cmd_t cmd)900Sstevel@tonic-gate pool_detach(dev_info_t *devi, ddi_detach_cmd_t cmd)
910Sstevel@tonic-gate {
920Sstevel@tonic-gate int ret = DDI_SUCCESS;
930Sstevel@tonic-gate
940Sstevel@tonic-gate switch (cmd) {
950Sstevel@tonic-gate case DDI_DETACH:
960Sstevel@tonic-gate pool_lock();
970Sstevel@tonic-gate if (pool_state == POOL_ENABLED) {
980Sstevel@tonic-gate ret = DDI_FAILURE;
990Sstevel@tonic-gate pool_unlock();
1000Sstevel@tonic-gate break;
1010Sstevel@tonic-gate }
1020Sstevel@tonic-gate ddi_remove_minor_node(devi, NULL);
1030Sstevel@tonic-gate pool_devi = NULL;
1040Sstevel@tonic-gate pool_unlock();
1050Sstevel@tonic-gate break;
1060Sstevel@tonic-gate default:
1070Sstevel@tonic-gate ret = DDI_FAILURE;
1080Sstevel@tonic-gate }
1090Sstevel@tonic-gate return (ret);
1100Sstevel@tonic-gate }
1110Sstevel@tonic-gate
1120Sstevel@tonic-gate static int
pool_attach(dev_info_t * devi,ddi_attach_cmd_t cmd)1130Sstevel@tonic-gate pool_attach(dev_info_t *devi, ddi_attach_cmd_t cmd)
1140Sstevel@tonic-gate {
1150Sstevel@tonic-gate switch (cmd) {
1160Sstevel@tonic-gate case DDI_ATTACH:
1170Sstevel@tonic-gate if (pool_devi != NULL)
1180Sstevel@tonic-gate return (DDI_FAILURE);
1190Sstevel@tonic-gate if (ddi_create_minor_node(devi, "poolctl", S_IFCHR,
1200Sstevel@tonic-gate POOL_CTL_PARENT, DDI_PSEUDO, 0) == DDI_FAILURE ||
1210Sstevel@tonic-gate ddi_create_minor_node(devi, "pool", S_IFCHR,
1220Sstevel@tonic-gate POOL_INFO_PARENT, DDI_PSEUDO, 0) == DDI_FAILURE) {
1230Sstevel@tonic-gate ddi_remove_minor_node(devi, NULL);
1240Sstevel@tonic-gate return (DDI_FAILURE);
1250Sstevel@tonic-gate }
1260Sstevel@tonic-gate pool_devi = devi;
1270Sstevel@tonic-gate ddi_report_dev(devi);
1280Sstevel@tonic-gate break;
1290Sstevel@tonic-gate case DDI_RESUME:
1300Sstevel@tonic-gate break;
1310Sstevel@tonic-gate default:
1320Sstevel@tonic-gate return (DDI_FAILURE);
1330Sstevel@tonic-gate }
1340Sstevel@tonic-gate return (DDI_SUCCESS);
1350Sstevel@tonic-gate
1360Sstevel@tonic-gate }
1370Sstevel@tonic-gate
1380Sstevel@tonic-gate /*
1390Sstevel@tonic-gate * There is only one instance of the pool control device, poolctl,
1400Sstevel@tonic-gate * and multiple instances of the pool info device, pool.
1410Sstevel@tonic-gate */
1420Sstevel@tonic-gate /*ARGSUSED*/
1430Sstevel@tonic-gate static int
pool_open(dev_t * devp,int flag,int otype,cred_t * credp)1440Sstevel@tonic-gate pool_open(dev_t *devp, int flag, int otype, cred_t *credp)
1450Sstevel@tonic-gate {
1460Sstevel@tonic-gate minor_t minor = getminor(*devp);
1470Sstevel@tonic-gate
1480Sstevel@tonic-gate if (otype != OTYP_CHR)
1490Sstevel@tonic-gate return (EINVAL);
1500Sstevel@tonic-gate
1510Sstevel@tonic-gate switch (minor) {
1520Sstevel@tonic-gate case POOL_CTL_PARENT:
1530Sstevel@tonic-gate if (secpolicy_pool(CRED()) != 0)
1540Sstevel@tonic-gate return (EPERM);
1550Sstevel@tonic-gate if (pool_lock_intr() != 0)
1560Sstevel@tonic-gate return (EINTR);
1570Sstevel@tonic-gate if (pool_openctl == 1) {
1580Sstevel@tonic-gate pool_unlock();
1590Sstevel@tonic-gate return (EBUSY);
1600Sstevel@tonic-gate }
1610Sstevel@tonic-gate pool_openctl = 1;
1620Sstevel@tonic-gate pool_unlock();
1630Sstevel@tonic-gate break;
1640Sstevel@tonic-gate case POOL_INFO_PARENT:
1650Sstevel@tonic-gate break;
1660Sstevel@tonic-gate default:
1670Sstevel@tonic-gate return (ENXIO);
1680Sstevel@tonic-gate }
1690Sstevel@tonic-gate return (0);
1700Sstevel@tonic-gate }
1710Sstevel@tonic-gate
1720Sstevel@tonic-gate /*ARGSUSED*/
1730Sstevel@tonic-gate static int
pool_close(dev_t dev,int flag,int otype,cred_t * credp)1740Sstevel@tonic-gate pool_close(dev_t dev, int flag, int otype, cred_t *credp)
1750Sstevel@tonic-gate {
1760Sstevel@tonic-gate if (otype != OTYP_CHR)
1770Sstevel@tonic-gate return (EINVAL);
1780Sstevel@tonic-gate if (getminor(dev) == 0) {
1790Sstevel@tonic-gate /*
1800Sstevel@tonic-gate * We could be closing the poolctl device without finishing
1810Sstevel@tonic-gate * the commit transaction first, so do that now.
1820Sstevel@tonic-gate */
1830Sstevel@tonic-gate pool_lock();
1840Sstevel@tonic-gate (void) pool_commit(0); /* cannot fail since arg is 0 */
1850Sstevel@tonic-gate pool_openctl = 0;
1860Sstevel@tonic-gate pool_unlock();
1870Sstevel@tonic-gate }
1880Sstevel@tonic-gate return (0);
1890Sstevel@tonic-gate }
1900Sstevel@tonic-gate
1910Sstevel@tonic-gate /*
1920Sstevel@tonic-gate * Main pool interface.
1930Sstevel@tonic-gate */
1940Sstevel@tonic-gate /* ARGSUSED4 */
1950Sstevel@tonic-gate static int
pool_ioctl(dev_t dev,int cmd,intptr_t arg,int mode,cred_t * credp,int * rvalp)1960Sstevel@tonic-gate pool_ioctl(dev_t dev, int cmd, intptr_t arg, int mode, cred_t *credp,
1970Sstevel@tonic-gate int *rvalp)
1980Sstevel@tonic-gate {
1990Sstevel@tonic-gate pool_xtransfer_t xtransfer;
2000Sstevel@tonic-gate pool_transfer_t transfer;
2010Sstevel@tonic-gate pool_destroy_t destroy;
2020Sstevel@tonic-gate pool_propget_t propget;
2030Sstevel@tonic-gate pool_propput_t propput;
2040Sstevel@tonic-gate pool_proprm_t proprm;
2050Sstevel@tonic-gate pool_status_t status;
2060Sstevel@tonic-gate pool_dissoc_t dissoc;
2070Sstevel@tonic-gate pool_create_t create;
2080Sstevel@tonic-gate pool_assoc_t assoc;
2090Sstevel@tonic-gate pool_bindq_t bindq;
2100Sstevel@tonic-gate pool_query_t query;
2110Sstevel@tonic-gate pool_bind_t bind;
2120Sstevel@tonic-gate #ifdef _MULTI_DATAMODEL
2130Sstevel@tonic-gate pool_xtransfer32_t xtransfer32;
2140Sstevel@tonic-gate pool_propput32_t propput32;
2150Sstevel@tonic-gate pool_propget32_t propget32;
2160Sstevel@tonic-gate pool_proprm32_t proprm32;
2170Sstevel@tonic-gate pool_query32_t query32;
2180Sstevel@tonic-gate #endif /* _MULTI_DATAMODEL */
2190Sstevel@tonic-gate char *kbuf = NULL;
2200Sstevel@tonic-gate size_t kbufsz = 0;
2210Sstevel@tonic-gate int snapshot = 0;
2220Sstevel@tonic-gate char *prop_name;
2230Sstevel@tonic-gate size_t size = 0;
2240Sstevel@tonic-gate nvlist_t *list;
2250Sstevel@tonic-gate nvpair_t *pair;
2260Sstevel@tonic-gate char *listbuf;
2270Sstevel@tonic-gate minor_t minor;
2280Sstevel@tonic-gate uint_t model;
2290Sstevel@tonic-gate id_t *id_buf;
2300Sstevel@tonic-gate int ret = 0;
2310Sstevel@tonic-gate
2320Sstevel@tonic-gate model = ddi_model_convert_from(mode & FMODELS);
2330Sstevel@tonic-gate minor = getminor(dev);
2340Sstevel@tonic-gate
2350Sstevel@tonic-gate /*
2360Sstevel@tonic-gate * Check basic permissions first.
2370Sstevel@tonic-gate */
2380Sstevel@tonic-gate switch (cmd) {
2390Sstevel@tonic-gate case POOL_STATUS:
2400Sstevel@tonic-gate case POOL_CREATE:
2410Sstevel@tonic-gate case POOL_ASSOC:
2420Sstevel@tonic-gate case POOL_DISSOC:
2430Sstevel@tonic-gate case POOL_DESTROY:
2440Sstevel@tonic-gate case POOL_TRANSFER:
2450Sstevel@tonic-gate case POOL_XTRANSFER:
2460Sstevel@tonic-gate case POOL_PROPPUT:
2470Sstevel@tonic-gate case POOL_PROPRM:
2480Sstevel@tonic-gate case POOL_COMMIT:
2490Sstevel@tonic-gate if (minor != POOL_CTL_PARENT)
2500Sstevel@tonic-gate return (EINVAL);
2510Sstevel@tonic-gate /*FALLTHROUGH*/
2520Sstevel@tonic-gate case POOL_BIND:
2530Sstevel@tonic-gate if (secpolicy_pool(CRED()) != 0)
2540Sstevel@tonic-gate return (EPERM);
2550Sstevel@tonic-gate break;
2560Sstevel@tonic-gate }
2570Sstevel@tonic-gate
2580Sstevel@tonic-gate switch (cmd) {
2590Sstevel@tonic-gate case POOL_STATUS:
2600Sstevel@tonic-gate if (ddi_copyin((void *)arg, &status,
2610Sstevel@tonic-gate sizeof (pool_status_t), mode) != 0)
2620Sstevel@tonic-gate return (EFAULT);
2630Sstevel@tonic-gate if (pool_lock_intr() != 0)
2640Sstevel@tonic-gate return (EINTR);
2650Sstevel@tonic-gate ret = pool_status(status.ps_io_state);
2660Sstevel@tonic-gate pool_unlock();
2670Sstevel@tonic-gate break;
2680Sstevel@tonic-gate case POOL_STATUSQ:
2690Sstevel@tonic-gate /*
2700Sstevel@tonic-gate * No need to grab pool_lock() to look at the current state.
2710Sstevel@tonic-gate */
2720Sstevel@tonic-gate status.ps_io_state = pool_state;
2730Sstevel@tonic-gate if (ddi_copyout(&status, (void *)arg,
2740Sstevel@tonic-gate sizeof (pool_status_t), mode) != 0)
2750Sstevel@tonic-gate return (EFAULT);
2760Sstevel@tonic-gate break;
2770Sstevel@tonic-gate case POOL_QUERY:
2780Sstevel@tonic-gate switch (model) {
2790Sstevel@tonic-gate #ifdef _MULTI_DATAMODEL
2800Sstevel@tonic-gate case DDI_MODEL_ILP32:
2810Sstevel@tonic-gate if (ddi_copyin((void *)arg, &query32,
2820Sstevel@tonic-gate sizeof (pool_query32_t), mode) != 0)
2830Sstevel@tonic-gate return (EFAULT);
2840Sstevel@tonic-gate query.pq_io_bufsize = query32.pq_io_bufsize;
2850Sstevel@tonic-gate query.pq_io_buf = (char *)(uintptr_t)query32.pq_io_buf;
2860Sstevel@tonic-gate break;
2870Sstevel@tonic-gate #endif /* _MULTI_DATAMODEL */
2880Sstevel@tonic-gate default:
2890Sstevel@tonic-gate case DDI_MODEL_NONE:
2900Sstevel@tonic-gate if (ddi_copyin((void *)arg, &query,
2910Sstevel@tonic-gate sizeof (pool_query_t), mode) != 0)
2920Sstevel@tonic-gate return (EFAULT);
2930Sstevel@tonic-gate }
2940Sstevel@tonic-gate if (pool_lock_intr() != 0)
2950Sstevel@tonic-gate return (EINTR);
2960Sstevel@tonic-gate if (pool_state == POOL_DISABLED) {
2970Sstevel@tonic-gate pool_unlock();
2980Sstevel@tonic-gate return (ENOTACTIVE);
2990Sstevel@tonic-gate }
3000Sstevel@tonic-gate if (minor != 0 && pool_buf != NULL) {
3010Sstevel@tonic-gate /*
3020Sstevel@tonic-gate * Return last snapshot if some
3030Sstevel@tonic-gate * transaction is still in progress
3040Sstevel@tonic-gate */
3050Sstevel@tonic-gate if (kbufsz != 0 && pool_bufsz > kbufsz) {
3060Sstevel@tonic-gate pool_unlock();
3070Sstevel@tonic-gate return (ENOMEM);
3080Sstevel@tonic-gate }
3090Sstevel@tonic-gate kbuf = pool_buf;
3100Sstevel@tonic-gate kbufsz = size = pool_bufsz;
3110Sstevel@tonic-gate snapshot = 1;
3120Sstevel@tonic-gate } else if (query.pq_io_bufsize != 0) {
3130Sstevel@tonic-gate kbufsz = query.pq_io_bufsize;
3140Sstevel@tonic-gate kbuf = kmem_alloc(kbufsz, KM_NOSLEEP);
3150Sstevel@tonic-gate if (kbuf == NULL) {
3160Sstevel@tonic-gate pool_unlock();
3170Sstevel@tonic-gate return (ENOMEM);
3180Sstevel@tonic-gate }
3190Sstevel@tonic-gate ret = pool_pack_conf(kbuf, kbufsz, &size);
3200Sstevel@tonic-gate } else {
3210Sstevel@tonic-gate ret = pool_pack_conf(NULL, 0, &size);
3220Sstevel@tonic-gate }
3230Sstevel@tonic-gate if (ret == 0) {
3240Sstevel@tonic-gate switch (model) {
3250Sstevel@tonic-gate #ifdef _MULTI_DATAMODEL
3260Sstevel@tonic-gate case DDI_MODEL_ILP32:
3270Sstevel@tonic-gate query32.pq_io_bufsize = size;
3280Sstevel@tonic-gate if (ddi_copyout((caddr_t)&query32, (void *)arg,
3290Sstevel@tonic-gate sizeof (pool_query32_t), mode) != 0)
3300Sstevel@tonic-gate ret = EFAULT;
3310Sstevel@tonic-gate break;
3320Sstevel@tonic-gate #endif /* _MULTI_DATAMODEL */
3330Sstevel@tonic-gate default:
3340Sstevel@tonic-gate case DDI_MODEL_NONE:
3350Sstevel@tonic-gate query.pq_io_bufsize = size;
3360Sstevel@tonic-gate if (ddi_copyout(&query, (void *)arg,
3370Sstevel@tonic-gate sizeof (pool_query_t), mode) != 0)
3380Sstevel@tonic-gate ret = EFAULT;
3390Sstevel@tonic-gate }
3400Sstevel@tonic-gate if (ret == 0 && query.pq_io_buf != NULL &&
3410Sstevel@tonic-gate ddi_copyout(kbuf, query.pq_io_buf, size, mode) != 0)
3420Sstevel@tonic-gate ret = EFAULT;
3430Sstevel@tonic-gate }
3440Sstevel@tonic-gate pool_unlock();
3450Sstevel@tonic-gate if (snapshot == 0)
3460Sstevel@tonic-gate kmem_free(kbuf, kbufsz);
3470Sstevel@tonic-gate break;
3480Sstevel@tonic-gate case POOL_CREATE:
3490Sstevel@tonic-gate if (ddi_copyin((void *)arg,
3500Sstevel@tonic-gate &create, sizeof (pool_create_t), mode) != 0)
3510Sstevel@tonic-gate return (EFAULT);
3520Sstevel@tonic-gate if (pool_lock_intr() != 0)
3530Sstevel@tonic-gate return (EINTR);
3540Sstevel@tonic-gate ret = pool_create(create.pc_o_type,
3550Sstevel@tonic-gate create.pc_o_sub_type, &create.pc_i_id);
3560Sstevel@tonic-gate pool_unlock();
3570Sstevel@tonic-gate if (ret == 0 && ddi_copyout(&create, (void *)arg,
3580Sstevel@tonic-gate sizeof (pool_create_t), mode) != 0)
3590Sstevel@tonic-gate ret = EFAULT;
3600Sstevel@tonic-gate break;
3610Sstevel@tonic-gate case POOL_ASSOC:
3620Sstevel@tonic-gate if (ddi_copyin((void *)arg, &assoc,
3630Sstevel@tonic-gate sizeof (pool_assoc_t), mode) != 0)
3640Sstevel@tonic-gate return (EFAULT);
3650Sstevel@tonic-gate if (pool_lock_intr() != 0)
3660Sstevel@tonic-gate return (EINTR);
3670Sstevel@tonic-gate ret = pool_assoc(assoc.pa_o_pool_id,
3680Sstevel@tonic-gate assoc.pa_o_id_type, assoc.pa_o_res_id);
3690Sstevel@tonic-gate pool_unlock();
3700Sstevel@tonic-gate break;
3710Sstevel@tonic-gate case POOL_DISSOC:
3720Sstevel@tonic-gate if (ddi_copyin((void *)arg, &dissoc,
3730Sstevel@tonic-gate sizeof (pool_dissoc_t), mode) != 0)
3740Sstevel@tonic-gate return (EFAULT);
3750Sstevel@tonic-gate if (pool_lock_intr() != 0)
3760Sstevel@tonic-gate return (EINTR);
3770Sstevel@tonic-gate ret = pool_dissoc(dissoc.pd_o_pool_id, dissoc.pd_o_id_type);
3780Sstevel@tonic-gate pool_unlock();
3790Sstevel@tonic-gate break;
3800Sstevel@tonic-gate case POOL_DESTROY:
3810Sstevel@tonic-gate if (ddi_copyin((void *)arg, &destroy,
3820Sstevel@tonic-gate sizeof (pool_destroy_t), mode) != 0)
3830Sstevel@tonic-gate return (EFAULT);
3840Sstevel@tonic-gate if (pool_lock_intr() != 0)
3850Sstevel@tonic-gate return (EINTR);
3860Sstevel@tonic-gate ret = pool_destroy(destroy.pd_o_type, destroy.pd_o_sub_type,
3870Sstevel@tonic-gate destroy.pd_o_id);
3880Sstevel@tonic-gate pool_unlock();
3890Sstevel@tonic-gate break;
3900Sstevel@tonic-gate case POOL_TRANSFER:
3910Sstevel@tonic-gate if (ddi_copyin((void *)arg, &transfer,
3920Sstevel@tonic-gate sizeof (pool_transfer_t), mode) != 0)
3930Sstevel@tonic-gate return (EFAULT);
3940Sstevel@tonic-gate if (pool_lock_intr() != 0)
3950Sstevel@tonic-gate return (EINTR);
3960Sstevel@tonic-gate ret = pool_transfer(transfer.pt_o_id_type, transfer.pt_o_src_id,
3970Sstevel@tonic-gate transfer.pt_o_tgt_id, transfer.pt_o_qty);
3980Sstevel@tonic-gate pool_unlock();
3990Sstevel@tonic-gate break;
4000Sstevel@tonic-gate case POOL_XTRANSFER:
4010Sstevel@tonic-gate switch (model) {
4020Sstevel@tonic-gate #ifdef _MULTI_DATAMODEL
4030Sstevel@tonic-gate case DDI_MODEL_ILP32:
4040Sstevel@tonic-gate if (ddi_copyin((void *)arg, &xtransfer32,
4050Sstevel@tonic-gate sizeof (pool_xtransfer32_t), mode) != 0)
4060Sstevel@tonic-gate return (EFAULT);
4070Sstevel@tonic-gate xtransfer.px_o_id_type = xtransfer32.px_o_id_type;
4080Sstevel@tonic-gate xtransfer.px_o_src_id = xtransfer32.px_o_src_id;
4090Sstevel@tonic-gate xtransfer.px_o_tgt_id = xtransfer32.px_o_tgt_id;
4100Sstevel@tonic-gate xtransfer.px_o_complist_size =
411*7656SSherry.Moore@Sun.COM xtransfer32.px_o_complist_size;
4120Sstevel@tonic-gate xtransfer.px_o_comp_list =
413*7656SSherry.Moore@Sun.COM (id_t *)(uintptr_t)xtransfer32.px_o_comp_list;
4140Sstevel@tonic-gate break;
4150Sstevel@tonic-gate #endif /* _MULTI_DATAMODEL */
4160Sstevel@tonic-gate default:
4170Sstevel@tonic-gate case DDI_MODEL_NONE:
4180Sstevel@tonic-gate if (ddi_copyin((void *)arg, &xtransfer,
4190Sstevel@tonic-gate sizeof (pool_xtransfer_t), mode) != 0)
4200Sstevel@tonic-gate return (EFAULT);
4210Sstevel@tonic-gate }
4220Sstevel@tonic-gate /*
4230Sstevel@tonic-gate * Copy in IDs to transfer from the userland
4240Sstevel@tonic-gate */
4250Sstevel@tonic-gate if (xtransfer.px_o_complist_size > POOL_IDLIST_SIZE)
4260Sstevel@tonic-gate return (EINVAL);
4270Sstevel@tonic-gate id_buf = kmem_alloc(xtransfer.px_o_complist_size *
4280Sstevel@tonic-gate sizeof (id_t), KM_SLEEP);
4290Sstevel@tonic-gate if (ddi_copyin((void *)xtransfer.px_o_comp_list, id_buf,
4300Sstevel@tonic-gate xtransfer.px_o_complist_size * sizeof (id_t), mode) != 0) {
4310Sstevel@tonic-gate kmem_free(id_buf, xtransfer.px_o_complist_size *
4320Sstevel@tonic-gate sizeof (id_t));
4330Sstevel@tonic-gate return (EFAULT);
4340Sstevel@tonic-gate }
4350Sstevel@tonic-gate if (pool_lock_intr() != 0) {
4360Sstevel@tonic-gate kmem_free(id_buf, xtransfer.px_o_complist_size *
4370Sstevel@tonic-gate sizeof (id_t));
4380Sstevel@tonic-gate return (EINTR);
4390Sstevel@tonic-gate }
4400Sstevel@tonic-gate ret = pool_xtransfer(xtransfer.px_o_id_type,
4410Sstevel@tonic-gate xtransfer.px_o_src_id, xtransfer.px_o_tgt_id,
4420Sstevel@tonic-gate xtransfer.px_o_complist_size, id_buf);
4430Sstevel@tonic-gate pool_unlock();
4440Sstevel@tonic-gate kmem_free(id_buf, xtransfer.px_o_complist_size *
4450Sstevel@tonic-gate sizeof (id_t));
4460Sstevel@tonic-gate break;
4470Sstevel@tonic-gate case POOL_BIND:
4480Sstevel@tonic-gate if (ddi_copyin((void *)arg, &bind,
4490Sstevel@tonic-gate sizeof (pool_bind_t), mode) != 0)
4500Sstevel@tonic-gate return (EFAULT);
4510Sstevel@tonic-gate if (pool_lock_intr() != 0)
4520Sstevel@tonic-gate return (EINTR);
4530Sstevel@tonic-gate ret = pool_bind(bind.pb_o_pool_id, bind.pb_o_id_type,
4540Sstevel@tonic-gate bind.pb_o_id);
4550Sstevel@tonic-gate pool_unlock();
4560Sstevel@tonic-gate break;
4570Sstevel@tonic-gate case POOL_BINDQ:
4580Sstevel@tonic-gate if (ddi_copyin((void *)arg, &bindq,
4590Sstevel@tonic-gate sizeof (pool_bindq_t), mode) != 0) {
4600Sstevel@tonic-gate return (EFAULT);
4610Sstevel@tonic-gate }
4620Sstevel@tonic-gate if (pool_lock_intr() != 0)
4630Sstevel@tonic-gate return (EINTR);
4640Sstevel@tonic-gate if ((ret = pool_query_binding(bindq.pb_o_id_type,
4650Sstevel@tonic-gate bindq.pb_o_id, &bindq.pb_i_id)) == 0 &&
4660Sstevel@tonic-gate ddi_copyout(&bindq, (void *)arg,
4670Sstevel@tonic-gate sizeof (pool_bindq_t), mode) != 0)
4680Sstevel@tonic-gate ret = EFAULT;
4690Sstevel@tonic-gate pool_unlock();
4700Sstevel@tonic-gate break;
4710Sstevel@tonic-gate case POOL_PROPGET:
4720Sstevel@tonic-gate switch (model) {
4730Sstevel@tonic-gate #ifdef _MULTI_DATAMODEL
4740Sstevel@tonic-gate case DDI_MODEL_ILP32:
4750Sstevel@tonic-gate if (ddi_copyin((void *)arg, &propget32,
4760Sstevel@tonic-gate sizeof (pool_propget32_t), mode) != 0)
4770Sstevel@tonic-gate return (EFAULT);
4780Sstevel@tonic-gate propget.pp_o_id = propget32.pp_o_id;
4790Sstevel@tonic-gate propget.pp_o_id_type = propget32.pp_o_id_type;
4800Sstevel@tonic-gate propget.pp_o_id_subtype = propget32.pp_o_id_subtype;
4810Sstevel@tonic-gate propget.pp_o_prop_name =
4820Sstevel@tonic-gate (char *)(uintptr_t)propget32.pp_o_prop_name;
4830Sstevel@tonic-gate propget.pp_o_prop_name_size =
4840Sstevel@tonic-gate propget32.pp_o_prop_name_size;
4850Sstevel@tonic-gate propget.pp_i_buf =
4860Sstevel@tonic-gate (char *)(uintptr_t)propget32.pp_i_buf;
4870Sstevel@tonic-gate propget.pp_i_bufsize = propget32.pp_i_bufsize;
4880Sstevel@tonic-gate break;
4890Sstevel@tonic-gate #endif /* _MULTI_DATAMODEL */
4900Sstevel@tonic-gate default:
4910Sstevel@tonic-gate case DDI_MODEL_NONE:
4920Sstevel@tonic-gate if (ddi_copyin((void *)arg, &propget,
4930Sstevel@tonic-gate sizeof (pool_propget_t), mode) != 0)
4940Sstevel@tonic-gate return (EFAULT);
4950Sstevel@tonic-gate }
4960Sstevel@tonic-gate if (propget.pp_o_prop_name_size + 1 > POOL_PROPNAME_SIZE)
4970Sstevel@tonic-gate return (EINVAL);
4980Sstevel@tonic-gate prop_name = kmem_alloc(propget.pp_o_prop_name_size + 1,
4990Sstevel@tonic-gate KM_SLEEP);
5000Sstevel@tonic-gate if (ddi_copyin(propget.pp_o_prop_name, prop_name,
5010Sstevel@tonic-gate propget.pp_o_prop_name_size + 1, mode) != 0) {
5020Sstevel@tonic-gate kmem_free(prop_name, propget.pp_o_prop_name_size + 1);
5030Sstevel@tonic-gate return (EFAULT);
5040Sstevel@tonic-gate }
5050Sstevel@tonic-gate list = NULL;
5060Sstevel@tonic-gate if (pool_lock_intr() != 0) {
5070Sstevel@tonic-gate kmem_free(prop_name, propget.pp_o_prop_name_size + 1);
5080Sstevel@tonic-gate return (EINTR);
5090Sstevel@tonic-gate }
5100Sstevel@tonic-gate ret = pool_propget(prop_name, propget.pp_o_id_type,
5110Sstevel@tonic-gate propget.pp_o_id_subtype, propget.pp_o_id, &list);
5120Sstevel@tonic-gate pool_unlock();
5130Sstevel@tonic-gate kmem_free(prop_name, propget.pp_o_prop_name_size + 1);
5140Sstevel@tonic-gate if (ret != 0)
5150Sstevel@tonic-gate return (ret);
5160Sstevel@tonic-gate ret = nvlist_pack(list, &kbuf, &kbufsz, NV_ENCODE_NATIVE, 0);
5170Sstevel@tonic-gate if (ret != 0) {
5180Sstevel@tonic-gate nvlist_free(list);
5190Sstevel@tonic-gate return (ret);
5200Sstevel@tonic-gate }
5210Sstevel@tonic-gate switch (model) {
5220Sstevel@tonic-gate #ifdef _MULTI_DATAMODEL
5230Sstevel@tonic-gate case DDI_MODEL_ILP32:
5240Sstevel@tonic-gate propget32.pp_i_bufsize = kbufsz;
5250Sstevel@tonic-gate if (ddi_copyout((caddr_t)&propget32, (void *)arg,
5260Sstevel@tonic-gate sizeof (pool_propget32_t), mode) != 0)
5270Sstevel@tonic-gate ret = EFAULT;
5280Sstevel@tonic-gate break;
5290Sstevel@tonic-gate #endif /* _MULTI_DATAMODEL */
5300Sstevel@tonic-gate default:
5310Sstevel@tonic-gate case DDI_MODEL_NONE:
5320Sstevel@tonic-gate if (ddi_copyout(&propget, (void *)arg,
5330Sstevel@tonic-gate sizeof (pool_propget_t), mode) != 0)
5340Sstevel@tonic-gate ret = EFAULT;
5350Sstevel@tonic-gate }
5360Sstevel@tonic-gate if (ret == 0) {
5370Sstevel@tonic-gate if (propget.pp_i_buf == NULL) {
5380Sstevel@tonic-gate ret = 0;
5390Sstevel@tonic-gate } else if (propget.pp_i_bufsize >= kbufsz) {
5400Sstevel@tonic-gate if (ddi_copyout(kbuf, propget.pp_i_buf,
5410Sstevel@tonic-gate kbufsz, mode) != 0)
5420Sstevel@tonic-gate ret = EFAULT;
5430Sstevel@tonic-gate } else {
5440Sstevel@tonic-gate ret = ENOMEM;
5450Sstevel@tonic-gate }
5460Sstevel@tonic-gate }
5470Sstevel@tonic-gate kmem_free(kbuf, kbufsz);
5480Sstevel@tonic-gate nvlist_free(list);
5490Sstevel@tonic-gate break;
5500Sstevel@tonic-gate case POOL_PROPPUT:
5510Sstevel@tonic-gate switch (model) {
5520Sstevel@tonic-gate #ifdef _MULTI_DATAMODEL
5530Sstevel@tonic-gate case DDI_MODEL_ILP32:
5540Sstevel@tonic-gate if (ddi_copyin((void *)arg, &propput32,
5550Sstevel@tonic-gate sizeof (pool_propput32_t), mode) != 0)
5560Sstevel@tonic-gate return (EFAULT);
5570Sstevel@tonic-gate propput.pp_o_id_type = propput32.pp_o_id_type;
5580Sstevel@tonic-gate propput.pp_o_id_sub_type = propput32.pp_o_id_sub_type;
5590Sstevel@tonic-gate propput.pp_o_id = propput32.pp_o_id;
5600Sstevel@tonic-gate propput.pp_o_bufsize = propput32.pp_o_bufsize;
5610Sstevel@tonic-gate propput.pp_o_buf =
5620Sstevel@tonic-gate (char *)(uintptr_t)propput32.pp_o_buf;
5630Sstevel@tonic-gate break;
5640Sstevel@tonic-gate #endif /* _MULTI_DATAMODEL */
5650Sstevel@tonic-gate default:
5660Sstevel@tonic-gate case DDI_MODEL_NONE:
5670Sstevel@tonic-gate if (ddi_copyin((void *)arg, &propput,
5680Sstevel@tonic-gate sizeof (pool_propput_t), mode) != 0)
5690Sstevel@tonic-gate return (EFAULT);
5700Sstevel@tonic-gate }
5710Sstevel@tonic-gate if (propput.pp_o_bufsize > POOL_PROPBUF_SIZE)
5720Sstevel@tonic-gate return (EINVAL);
5730Sstevel@tonic-gate listbuf = kmem_alloc(propput.pp_o_bufsize, KM_SLEEP);
5740Sstevel@tonic-gate if (ddi_copyin(propput.pp_o_buf, listbuf,
5750Sstevel@tonic-gate propput.pp_o_bufsize, mode) != 0) {
5760Sstevel@tonic-gate kmem_free(listbuf, propput.pp_o_bufsize);
5770Sstevel@tonic-gate return (EFAULT);
5780Sstevel@tonic-gate }
5790Sstevel@tonic-gate if (nvlist_unpack(listbuf, propput.pp_o_bufsize,
580*7656SSherry.Moore@Sun.COM &list, KM_SLEEP) != 0) {
5810Sstevel@tonic-gate kmem_free(listbuf, propput.pp_o_bufsize);
5820Sstevel@tonic-gate return (EFAULT);
5830Sstevel@tonic-gate }
5840Sstevel@tonic-gate if (pool_lock_intr() != 0) {
5850Sstevel@tonic-gate nvlist_free(list);
5860Sstevel@tonic-gate kmem_free(listbuf, propput.pp_o_bufsize);
5870Sstevel@tonic-gate return (EINTR);
5880Sstevel@tonic-gate }
5890Sstevel@tonic-gate /*
5900Sstevel@tonic-gate * Extract the nvpair from the list. The list may
5910Sstevel@tonic-gate * contain multiple properties.
5920Sstevel@tonic-gate */
5930Sstevel@tonic-gate for (pair = nvlist_next_nvpair(list, NULL); pair != NULL;
5940Sstevel@tonic-gate pair = nvlist_next_nvpair(list, pair)) {
5950Sstevel@tonic-gate if ((ret = pool_propput(propput.pp_o_id_type,
5960Sstevel@tonic-gate propput.pp_o_id_sub_type,
5970Sstevel@tonic-gate propput.pp_o_id, pair)) != 0)
5980Sstevel@tonic-gate break;
5990Sstevel@tonic-gate }
6000Sstevel@tonic-gate pool_unlock();
6010Sstevel@tonic-gate nvlist_free(list);
6020Sstevel@tonic-gate kmem_free(listbuf, propput.pp_o_bufsize);
6030Sstevel@tonic-gate break;
6040Sstevel@tonic-gate case POOL_PROPRM:
6050Sstevel@tonic-gate switch (model) {
6060Sstevel@tonic-gate #ifdef _MULTI_DATAMODEL
6070Sstevel@tonic-gate case DDI_MODEL_ILP32:
6080Sstevel@tonic-gate if (ddi_copyin((void *)arg, &proprm32,
6090Sstevel@tonic-gate sizeof (pool_proprm32_t), mode) != 0)
6100Sstevel@tonic-gate return (EFAULT);
6110Sstevel@tonic-gate proprm.pp_o_id_type = proprm32.pp_o_id_type;
6120Sstevel@tonic-gate proprm.pp_o_id_sub_type = proprm32.pp_o_id_sub_type;
6130Sstevel@tonic-gate proprm.pp_o_id = proprm32.pp_o_id;
6140Sstevel@tonic-gate proprm.pp_o_prop_name_size =
6150Sstevel@tonic-gate proprm32.pp_o_prop_name_size;
6160Sstevel@tonic-gate proprm.pp_o_prop_name =
6170Sstevel@tonic-gate (void *)(uintptr_t)proprm32.pp_o_prop_name;
6180Sstevel@tonic-gate break;
6190Sstevel@tonic-gate #endif /* _MULTI_DATAMODEL */
6200Sstevel@tonic-gate default:
6210Sstevel@tonic-gate case DDI_MODEL_NONE:
6220Sstevel@tonic-gate if (ddi_copyin((void *)arg, &proprm,
6230Sstevel@tonic-gate sizeof (pool_proprm_t), mode) != 0)
6240Sstevel@tonic-gate return (EFAULT);
6250Sstevel@tonic-gate }
6260Sstevel@tonic-gate if (proprm.pp_o_prop_name_size + 1 > POOL_PROPNAME_SIZE)
6270Sstevel@tonic-gate return (EINVAL);
6280Sstevel@tonic-gate prop_name = kmem_alloc(proprm.pp_o_prop_name_size + 1,
6290Sstevel@tonic-gate KM_SLEEP);
6300Sstevel@tonic-gate if (ddi_copyin(proprm.pp_o_prop_name, prop_name,
6310Sstevel@tonic-gate proprm.pp_o_prop_name_size + 1, mode) != 0) {
6320Sstevel@tonic-gate kmem_free(prop_name, proprm.pp_o_prop_name_size + 1);
6330Sstevel@tonic-gate return (EFAULT);
6340Sstevel@tonic-gate }
6350Sstevel@tonic-gate if (pool_lock_intr() != 0) {
6360Sstevel@tonic-gate kmem_free(prop_name, proprm.pp_o_prop_name_size + 1);
6370Sstevel@tonic-gate return (EINTR);
6380Sstevel@tonic-gate }
6390Sstevel@tonic-gate ret = pool_proprm(proprm.pp_o_id_type,
6400Sstevel@tonic-gate proprm.pp_o_id_sub_type, proprm.pp_o_id, prop_name);
6410Sstevel@tonic-gate pool_unlock();
6420Sstevel@tonic-gate kmem_free(prop_name, proprm.pp_o_prop_name_size + 1);
6430Sstevel@tonic-gate break;
6440Sstevel@tonic-gate case POOL_COMMIT:
6450Sstevel@tonic-gate if (pool_lock_intr() != 0)
6460Sstevel@tonic-gate return (EINTR);
6470Sstevel@tonic-gate ret = pool_commit((int)arg);
6480Sstevel@tonic-gate pool_unlock();
6490Sstevel@tonic-gate break;
6500Sstevel@tonic-gate default:
6510Sstevel@tonic-gate return (EINVAL);
6520Sstevel@tonic-gate }
6530Sstevel@tonic-gate return (ret);
6540Sstevel@tonic-gate }
6550Sstevel@tonic-gate
6560Sstevel@tonic-gate static struct cb_ops pool_cb_ops = {
6570Sstevel@tonic-gate pool_open, /* open */
6580Sstevel@tonic-gate pool_close, /* close */
6590Sstevel@tonic-gate nodev, /* strategy */
6600Sstevel@tonic-gate nodev, /* print */
6610Sstevel@tonic-gate nodev, /* dump */
6620Sstevel@tonic-gate nodev, /* read */
6630Sstevel@tonic-gate nodev, /* write */
6640Sstevel@tonic-gate pool_ioctl, /* ioctl */
6650Sstevel@tonic-gate nodev, /* devmap */
6660Sstevel@tonic-gate nodev, /* mmap */
6670Sstevel@tonic-gate nodev, /* segmap */
6680Sstevel@tonic-gate nochpoll, /* poll */
6690Sstevel@tonic-gate nodev, /* cb_prop_op */
6700Sstevel@tonic-gate (struct streamtab *)0, /* streamtab */
6710Sstevel@tonic-gate D_NEW | D_MP /* driver compatibility flags */
6720Sstevel@tonic-gate };
6730Sstevel@tonic-gate
6740Sstevel@tonic-gate static struct dev_ops pool_ops = {
6750Sstevel@tonic-gate DEVO_REV, /* devo_rev */
6760Sstevel@tonic-gate 0, /* refcnt */
6770Sstevel@tonic-gate pool_info, /* info */
6780Sstevel@tonic-gate nulldev, /* identify */
6790Sstevel@tonic-gate nulldev, /* probe */
6800Sstevel@tonic-gate pool_attach, /* attach */
6810Sstevel@tonic-gate pool_detach, /* detach */
6820Sstevel@tonic-gate nodev, /* reset */
6830Sstevel@tonic-gate &pool_cb_ops, /* cb_ops */
6840Sstevel@tonic-gate (struct bus_ops *)NULL, /* bus_ops */
685*7656SSherry.Moore@Sun.COM nulldev, /* power */
686*7656SSherry.Moore@Sun.COM ddi_quiesce_not_needed, /* quiesce */
6870Sstevel@tonic-gate };
6880Sstevel@tonic-gate
6890Sstevel@tonic-gate /*
6900Sstevel@tonic-gate * Module linkage information for the kernel
6910Sstevel@tonic-gate */
6920Sstevel@tonic-gate static struct modldrv modldrv = {
6930Sstevel@tonic-gate &mod_driverops, /* this one is a pseudo driver */
694*7656SSherry.Moore@Sun.COM "pool driver",
6950Sstevel@tonic-gate &pool_ops
6960Sstevel@tonic-gate };
6970Sstevel@tonic-gate
6980Sstevel@tonic-gate static struct modlinkage modlinkage = {
6990Sstevel@tonic-gate MODREV_1,
7000Sstevel@tonic-gate &modldrv,
7010Sstevel@tonic-gate NULL
7020Sstevel@tonic-gate };
7030Sstevel@tonic-gate
7040Sstevel@tonic-gate int
_init(void)7050Sstevel@tonic-gate _init(void)
7060Sstevel@tonic-gate {
7070Sstevel@tonic-gate return (mod_install(&modlinkage));
7080Sstevel@tonic-gate }
7090Sstevel@tonic-gate
7100Sstevel@tonic-gate int
_fini(void)7110Sstevel@tonic-gate _fini(void)
7120Sstevel@tonic-gate {
7130Sstevel@tonic-gate return (mod_remove(&modlinkage));
7140Sstevel@tonic-gate }
7150Sstevel@tonic-gate
7160Sstevel@tonic-gate int
_info(struct modinfo * modinfop)7170Sstevel@tonic-gate _info(struct modinfo *modinfop)
7180Sstevel@tonic-gate {
7190Sstevel@tonic-gate return (mod_info(&modlinkage, modinfop));
7200Sstevel@tonic-gate }
721