11d4b38e0Srsmaeda /* 21d4b38e0Srsmaeda * CDDL HEADER START 31d4b38e0Srsmaeda * 41d4b38e0Srsmaeda * The contents of this file are subject to the terms of the 51d4b38e0Srsmaeda * Common Development and Distribution License (the "License"). 61d4b38e0Srsmaeda * You may not use this file except in compliance with the License. 71d4b38e0Srsmaeda * 81d4b38e0Srsmaeda * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 91d4b38e0Srsmaeda * or http://www.opensolaris.org/os/licensing. 101d4b38e0Srsmaeda * See the License for the specific language governing permissions 111d4b38e0Srsmaeda * and limitations under the License. 121d4b38e0Srsmaeda * 131d4b38e0Srsmaeda * When distributing Covered Code, include this CDDL HEADER in each 141d4b38e0Srsmaeda * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 151d4b38e0Srsmaeda * If applicable, add the following below this CDDL HEADER, with the 161d4b38e0Srsmaeda * fields enclosed by brackets "[]" replaced with your own identifying 171d4b38e0Srsmaeda * information: Portions Copyright [yyyy] [name of copyright owner] 181d4b38e0Srsmaeda * 191d4b38e0Srsmaeda * CDDL HEADER END 201d4b38e0Srsmaeda */ 211d4b38e0Srsmaeda 221d4b38e0Srsmaeda /* 231d4b38e0Srsmaeda * Copyright 2006 Sun Microsystems, Inc. All rights reserved. 241d4b38e0Srsmaeda * Use is subject to license terms. 251d4b38e0Srsmaeda */ 261d4b38e0Srsmaeda 271d4b38e0Srsmaeda #pragma ident "%Z%%M% %I% %E% SMI" 281d4b38e0Srsmaeda 291d4b38e0Srsmaeda /* 301d4b38e0Srsmaeda * DR control module for LDoms 311d4b38e0Srsmaeda */ 321d4b38e0Srsmaeda 331d4b38e0Srsmaeda #include <sys/sysmacros.h> 341d4b38e0Srsmaeda #include <sys/modctl.h> 351d4b38e0Srsmaeda #include <sys/conf.h> 361d4b38e0Srsmaeda #include <sys/ddi.h> 371d4b38e0Srsmaeda #include <sys/sunddi.h> 381d4b38e0Srsmaeda #include <sys/ddi_impldefs.h> 391d4b38e0Srsmaeda #include <sys/stat.h> 401d4b38e0Srsmaeda #include <sys/door.h> 411d4b38e0Srsmaeda #include <sys/open.h> 421d4b38e0Srsmaeda #include <sys/note.h> 431d4b38e0Srsmaeda #include <sys/ldoms.h> 441d4b38e0Srsmaeda #include <sys/dr_util.h> 451d4b38e0Srsmaeda #include <sys/drctl.h> 461d4b38e0Srsmaeda #include <sys/drctl_impl.h> 471d4b38e0Srsmaeda 481d4b38e0Srsmaeda 491d4b38e0Srsmaeda static int drctl_attach(dev_info_t *, ddi_attach_cmd_t); 501d4b38e0Srsmaeda static int drctl_detach(dev_info_t *, ddi_detach_cmd_t); 511d4b38e0Srsmaeda static int drctl_getinfo(dev_info_t *, ddi_info_cmd_t, void *, void **); 521d4b38e0Srsmaeda 531d4b38e0Srsmaeda static int drctl_open(dev_t *, int, int, cred_t *); 541d4b38e0Srsmaeda static int drctl_close(dev_t, int, int, cred_t *); 551d4b38e0Srsmaeda static int drctl_ioctl(dev_t, int, intptr_t, int, cred_t *, int *); 561d4b38e0Srsmaeda 571d4b38e0Srsmaeda static void *pack_message(int, int, int, void *, size_t *); 581d4b38e0Srsmaeda static int send_message(void *, size_t, void **, size_t *); 591d4b38e0Srsmaeda 601d4b38e0Srsmaeda 611d4b38e0Srsmaeda /* 621d4b38e0Srsmaeda * Configuration data structures 631d4b38e0Srsmaeda */ 641d4b38e0Srsmaeda static struct cb_ops drctl_cb_ops = { 651d4b38e0Srsmaeda drctl_open, /* open */ 661d4b38e0Srsmaeda drctl_close, /* close */ 671d4b38e0Srsmaeda nodev, /* strategy */ 681d4b38e0Srsmaeda nodev, /* print */ 691d4b38e0Srsmaeda nodev, /* dump */ 701d4b38e0Srsmaeda nodev, /* read */ 711d4b38e0Srsmaeda nodev, /* write */ 721d4b38e0Srsmaeda drctl_ioctl, /* ioctl */ 731d4b38e0Srsmaeda nodev, /* devmap */ 741d4b38e0Srsmaeda nodev, /* mmap */ 751d4b38e0Srsmaeda nodev, /* segmap */ 761d4b38e0Srsmaeda nochpoll, /* poll */ 771d4b38e0Srsmaeda ddi_prop_op, /* prop_op */ 781d4b38e0Srsmaeda NULL, /* streamtab */ 791d4b38e0Srsmaeda D_MP | D_NEW, /* driver compatibility flag */ 801d4b38e0Srsmaeda CB_REV, /* cb_ops revision */ 811d4b38e0Srsmaeda nodev, /* async read */ 821d4b38e0Srsmaeda nodev /* async write */ 831d4b38e0Srsmaeda }; 841d4b38e0Srsmaeda 851d4b38e0Srsmaeda 861d4b38e0Srsmaeda static struct dev_ops drctl_ops = { 871d4b38e0Srsmaeda DEVO_REV, /* devo_rev */ 881d4b38e0Srsmaeda 0, /* refcnt */ 891d4b38e0Srsmaeda drctl_getinfo, /* info */ 901d4b38e0Srsmaeda nulldev, /* identify */ 911d4b38e0Srsmaeda nulldev, /* probe */ 921d4b38e0Srsmaeda drctl_attach, /* attach */ 931d4b38e0Srsmaeda drctl_detach, /* detach */ 941d4b38e0Srsmaeda nodev, /* reset */ 951d4b38e0Srsmaeda &drctl_cb_ops, /* driver operations */ 961d4b38e0Srsmaeda NULL, /* bus operations */ 971d4b38e0Srsmaeda NULL, /* power */ 981d4b38e0Srsmaeda }; 991d4b38e0Srsmaeda 1001d4b38e0Srsmaeda static struct modldrv modldrv = { 1011d4b38e0Srsmaeda &mod_driverops, /* type of module - driver */ 1021d4b38e0Srsmaeda "DR Control pseudo driver v%I%", 1031d4b38e0Srsmaeda &drctl_ops 1041d4b38e0Srsmaeda }; 1051d4b38e0Srsmaeda 1061d4b38e0Srsmaeda static struct modlinkage modlinkage = { 1071d4b38e0Srsmaeda MODREV_1, 1081d4b38e0Srsmaeda &modldrv, 1091d4b38e0Srsmaeda NULL 1101d4b38e0Srsmaeda }; 1111d4b38e0Srsmaeda 1121d4b38e0Srsmaeda 1131d4b38e0Srsmaeda /* 1141d4b38e0Srsmaeda * Locking strategy 1151d4b38e0Srsmaeda * 1161d4b38e0Srsmaeda * One of the reasons for this module's existence is to serialize 1171d4b38e0Srsmaeda * DR requests which might be coming from different sources. Only 1181d4b38e0Srsmaeda * one operation is allowed to be in progress at any given time. 1191d4b38e0Srsmaeda * 1201d4b38e0Srsmaeda * A single lock word (the 'drc_busy' element below) is NULL 1211d4b38e0Srsmaeda * when there is no operation in progress. When a client of this 1221d4b38e0Srsmaeda * module initiates an operation it grabs the mutex 'drc_lock' in 1231d4b38e0Srsmaeda * order to examine the lock word ('drc_busy'). If no other 1241d4b38e0Srsmaeda * operation is in progress, the lock word will be NULL. If so, 1251d4b38e0Srsmaeda * a cookie which uniquely identifies the requestor is stored in 1261d4b38e0Srsmaeda * the lock word, and the mutex is released. Attempts by other 1271d4b38e0Srsmaeda * clients to initiate an operation will fail. 1281d4b38e0Srsmaeda * 1291d4b38e0Srsmaeda * When the lock-holding client's operation is completed, the 1301d4b38e0Srsmaeda * client will call a "finalize" function in this module, providing 1311d4b38e0Srsmaeda * the cookie passed with the original request. Since the cookie 1321d4b38e0Srsmaeda * matches, the operation will succeed and the lock word will be 1331d4b38e0Srsmaeda * cleared. At this point, an new operation may be initiated. 1341d4b38e0Srsmaeda */ 1351d4b38e0Srsmaeda 1361d4b38e0Srsmaeda /* 1371d4b38e0Srsmaeda * Driver private data 1381d4b38e0Srsmaeda */ 1391d4b38e0Srsmaeda static struct drctl_unit { 1401d4b38e0Srsmaeda kmutex_t drc_lock; /* global driver lock */ 1411d4b38e0Srsmaeda dev_info_t *drc_dip; /* dev_info pointer */ 1421d4b38e0Srsmaeda kcondvar_t drc_busy_cv; /* block for !busy */ 1431d4b38e0Srsmaeda drctl_cookie_t drc_busy; /* NULL if free else a unique */ 1441d4b38e0Srsmaeda /* identifier for caller */ 1451d4b38e0Srsmaeda int drc_cmd; /* the cmd underway (or -1) */ 1461d4b38e0Srsmaeda int drc_flags; /* saved flag from above cmd */ 1471d4b38e0Srsmaeda int drc_inst; /* our single instance */ 1481d4b38e0Srsmaeda uint_t drc_state; /* driver state */ 1491d4b38e0Srsmaeda } drctl_state; 1501d4b38e0Srsmaeda 1511d4b38e0Srsmaeda static struct drctl_unit *drctlp = &drctl_state; 1521d4b38e0Srsmaeda 1531d4b38e0Srsmaeda int 1541d4b38e0Srsmaeda _init(void) 1551d4b38e0Srsmaeda { 156*e1ebb9ecSlm66018 int rv; 157*e1ebb9ecSlm66018 1581d4b38e0Srsmaeda drctlp->drc_inst = -1; 1591d4b38e0Srsmaeda mutex_init(&drctlp->drc_lock, NULL, MUTEX_DRIVER, NULL); 160*e1ebb9ecSlm66018 161*e1ebb9ecSlm66018 if ((rv = mod_install(&modlinkage)) != 0) 162*e1ebb9ecSlm66018 mutex_destroy(&drctlp->drc_lock); 163*e1ebb9ecSlm66018 164*e1ebb9ecSlm66018 return (rv); 1651d4b38e0Srsmaeda } 1661d4b38e0Srsmaeda 1671d4b38e0Srsmaeda 1681d4b38e0Srsmaeda int 1691d4b38e0Srsmaeda _fini(void) 1701d4b38e0Srsmaeda { 171*e1ebb9ecSlm66018 int rv; 172*e1ebb9ecSlm66018 173*e1ebb9ecSlm66018 if ((rv = mod_remove(&modlinkage)) != 0) 174*e1ebb9ecSlm66018 return (rv); 175*e1ebb9ecSlm66018 1761d4b38e0Srsmaeda mutex_destroy(&drctlp->drc_lock); 177*e1ebb9ecSlm66018 return (0); 1781d4b38e0Srsmaeda } 1791d4b38e0Srsmaeda 1801d4b38e0Srsmaeda 1811d4b38e0Srsmaeda int 1821d4b38e0Srsmaeda _info(struct modinfo *modinfop) 1831d4b38e0Srsmaeda { 1841d4b38e0Srsmaeda return (mod_info(&modlinkage, modinfop)); 1851d4b38e0Srsmaeda } 1861d4b38e0Srsmaeda 1871d4b38e0Srsmaeda 1881d4b38e0Srsmaeda /* 1891d4b38e0Srsmaeda * Do the attach work 1901d4b38e0Srsmaeda */ 1911d4b38e0Srsmaeda static int 1921d4b38e0Srsmaeda drctl_do_attach(dev_info_t *dip, ddi_attach_cmd_t cmd) 1931d4b38e0Srsmaeda { 1941d4b38e0Srsmaeda _NOTE(ARGUNUSED(cmd)) 1951d4b38e0Srsmaeda 1961d4b38e0Srsmaeda char *str = "drctl_do_attach"; 1971d4b38e0Srsmaeda int retval = DDI_SUCCESS; 1981d4b38e0Srsmaeda 1991d4b38e0Srsmaeda if (drctlp->drc_inst != -1) { 2001d4b38e0Srsmaeda cmn_err(CE_WARN, "%s: an instance is already attached!", str); 2011d4b38e0Srsmaeda return (DDI_FAILURE); 2021d4b38e0Srsmaeda } 2031d4b38e0Srsmaeda drctlp->drc_inst = ddi_get_instance(dip); 2041d4b38e0Srsmaeda 2051d4b38e0Srsmaeda retval = ddi_create_minor_node(dip, "drctl", S_IFCHR, 2061d4b38e0Srsmaeda drctlp->drc_inst, DDI_PSEUDO, 0); 2071d4b38e0Srsmaeda if (retval != DDI_SUCCESS) { 2081d4b38e0Srsmaeda cmn_err(CE_WARN, "%s: can't create minor node", str); 2091d4b38e0Srsmaeda drctlp->drc_inst = -1; 2101d4b38e0Srsmaeda return (retval); 2111d4b38e0Srsmaeda } 2121d4b38e0Srsmaeda 2131d4b38e0Srsmaeda drctlp->drc_dip = dip; 2141d4b38e0Srsmaeda ddi_report_dev(dip); 2151d4b38e0Srsmaeda 2161d4b38e0Srsmaeda return (retval); 2171d4b38e0Srsmaeda } 2181d4b38e0Srsmaeda 2191d4b38e0Srsmaeda 2201d4b38e0Srsmaeda static int 2211d4b38e0Srsmaeda drctl_attach(dev_info_t *dip, ddi_attach_cmd_t cmd) 2221d4b38e0Srsmaeda { 2231d4b38e0Srsmaeda switch (cmd) { 2241d4b38e0Srsmaeda case DDI_ATTACH: 2251d4b38e0Srsmaeda return (drctl_do_attach(dip, cmd)); 2261d4b38e0Srsmaeda 2271d4b38e0Srsmaeda default: 2281d4b38e0Srsmaeda return (DDI_FAILURE); 2291d4b38e0Srsmaeda } 2301d4b38e0Srsmaeda } 2311d4b38e0Srsmaeda 2321d4b38e0Srsmaeda 2331d4b38e0Srsmaeda /* ARGSUSED */ 2341d4b38e0Srsmaeda static int 2351d4b38e0Srsmaeda drctl_detach(dev_info_t *dip, ddi_detach_cmd_t cmd) 2361d4b38e0Srsmaeda { 2371d4b38e0Srsmaeda switch (cmd) { 2381d4b38e0Srsmaeda case DDI_DETACH: 2391d4b38e0Srsmaeda drctlp->drc_inst = -1; 2401d4b38e0Srsmaeda ddi_remove_minor_node(dip, "drctl"); 2411d4b38e0Srsmaeda return (DDI_SUCCESS); 2421d4b38e0Srsmaeda 2431d4b38e0Srsmaeda default: 2441d4b38e0Srsmaeda return (DDI_FAILURE); 2451d4b38e0Srsmaeda } 2461d4b38e0Srsmaeda } 2471d4b38e0Srsmaeda 2481d4b38e0Srsmaeda static int 2491d4b38e0Srsmaeda drctl_getinfo(dev_info_t *dip, ddi_info_cmd_t cmd, void *arg, void **resultp) 2501d4b38e0Srsmaeda { 2511d4b38e0Srsmaeda _NOTE(ARGUNUSED(dip, cmd, arg, resultp)) 2521d4b38e0Srsmaeda 2531d4b38e0Srsmaeda return (0); 2541d4b38e0Srsmaeda } 2551d4b38e0Srsmaeda 2561d4b38e0Srsmaeda static int 2571d4b38e0Srsmaeda drctl_open(dev_t *devp, int flag, int otyp, cred_t *cred_p) 2581d4b38e0Srsmaeda { 2591d4b38e0Srsmaeda _NOTE(ARGUNUSED(devp, flag, cred_p)) 2601d4b38e0Srsmaeda 2611d4b38e0Srsmaeda if (otyp != OTYP_CHR) 2621d4b38e0Srsmaeda return (EINVAL); 2631d4b38e0Srsmaeda 2641d4b38e0Srsmaeda return (0); 2651d4b38e0Srsmaeda } 2661d4b38e0Srsmaeda 2671d4b38e0Srsmaeda static int 2681d4b38e0Srsmaeda drctl_close(dev_t dev, int flag, int otyp, cred_t *cred_p) 2691d4b38e0Srsmaeda { 2701d4b38e0Srsmaeda _NOTE(ARGUNUSED(dev, flag, otyp, cred_p)) 2711d4b38e0Srsmaeda 2721d4b38e0Srsmaeda return (0); 2731d4b38e0Srsmaeda } 2741d4b38e0Srsmaeda 2751d4b38e0Srsmaeda /* 2761d4b38e0Srsmaeda * This driver guarantees that if drctl_config_init returns 0, 2771d4b38e0Srsmaeda * a valid response buffer will be passed back to the caller. This 2781d4b38e0Srsmaeda * routine can be used to generate that response in cases where the 2791d4b38e0Srsmaeda * upcall has not resulted in a response message from userland. 2801d4b38e0Srsmaeda */ 2811d4b38e0Srsmaeda static drctl_rsrc_t * 2821d4b38e0Srsmaeda drctl_generate_resp(drctl_rsrc_t *res, 2831d4b38e0Srsmaeda int count, size_t *rsize, drctl_status_t status) 2841d4b38e0Srsmaeda { 2851d4b38e0Srsmaeda int idx; 2861d4b38e0Srsmaeda size_t size; 2871d4b38e0Srsmaeda drctl_rsrc_t *rbuf; 2881d4b38e0Srsmaeda 2891d4b38e0Srsmaeda size = count * sizeof (*res); 2901d4b38e0Srsmaeda rbuf = kmem_alloc(size, KM_SLEEP); 2911d4b38e0Srsmaeda 2921d4b38e0Srsmaeda bcopy(res, rbuf, size); 2931d4b38e0Srsmaeda 2941d4b38e0Srsmaeda for (idx = 0; idx < count; idx++) { 2951d4b38e0Srsmaeda rbuf[idx].status = status; 2961d4b38e0Srsmaeda rbuf[idx].offset = 0; 2971d4b38e0Srsmaeda } 2981d4b38e0Srsmaeda 2991d4b38e0Srsmaeda *rsize = size; 3001d4b38e0Srsmaeda return (rbuf); 3011d4b38e0Srsmaeda } 3021d4b38e0Srsmaeda 3031d4b38e0Srsmaeda static int 3041d4b38e0Srsmaeda drctl_config_common(int cmd, int flags, drctl_rsrc_t *res, 3051d4b38e0Srsmaeda int count, drctl_rsrc_t **rbuf, size_t *rsize) 3061d4b38e0Srsmaeda { 3071d4b38e0Srsmaeda int rv = 0; 3081d4b38e0Srsmaeda size_t size; 3091d4b38e0Srsmaeda char *bufp; 3101d4b38e0Srsmaeda static const char me[] = "drctl_config_common"; 3111d4b38e0Srsmaeda 3121d4b38e0Srsmaeda switch (cmd) { 3131d4b38e0Srsmaeda case DRCTL_CPU_CONFIG_REQUEST: 3141d4b38e0Srsmaeda case DRCTL_CPU_CONFIG_NOTIFY: 3151d4b38e0Srsmaeda case DRCTL_CPU_UNCONFIG_REQUEST: 3161d4b38e0Srsmaeda case DRCTL_CPU_UNCONFIG_NOTIFY: 3171d4b38e0Srsmaeda rv = 0; 3181d4b38e0Srsmaeda break; 3191d4b38e0Srsmaeda case DRCTL_MEM_CONFIG_REQUEST: 3201d4b38e0Srsmaeda case DRCTL_MEM_CONFIG_NOTIFY: 3211d4b38e0Srsmaeda case DRCTL_MEM_UNCONFIG_REQUEST: 3221d4b38e0Srsmaeda case DRCTL_MEM_UNCONFIG_NOTIFY: 3231d4b38e0Srsmaeda case DRCTL_IO_CONFIG_REQUEST: 3241d4b38e0Srsmaeda case DRCTL_IO_CONFIG_NOTIFY: 3251d4b38e0Srsmaeda case DRCTL_IO_UNCONFIG_REQUEST: 3261d4b38e0Srsmaeda case DRCTL_IO_UNCONFIG_NOTIFY: 3271d4b38e0Srsmaeda rv = ENOTSUP; 3281d4b38e0Srsmaeda break; 3291d4b38e0Srsmaeda } 3301d4b38e0Srsmaeda 3311d4b38e0Srsmaeda if (rv != 0) { 3321d4b38e0Srsmaeda DR_DBG_CTL("%s: invalid cmd %d\n", me, cmd); 3331d4b38e0Srsmaeda return (rv); 3341d4b38e0Srsmaeda } 3351d4b38e0Srsmaeda 3361d4b38e0Srsmaeda /* 3371d4b38e0Srsmaeda * If the operation is a FORCE, we don't send a message to 3381d4b38e0Srsmaeda * the daemon. But, the upstream clients still expect a 3391d4b38e0Srsmaeda * response, so generate a response with all ops 'allowed'. 3401d4b38e0Srsmaeda */ 3411d4b38e0Srsmaeda if (flags == DRCTL_FLAG_FORCE) { 3421d4b38e0Srsmaeda if (rbuf != NULL) { 3431d4b38e0Srsmaeda *rbuf = drctl_generate_resp(res, count, &size, 3441d4b38e0Srsmaeda DRCTL_STATUS_ALLOW); 3451d4b38e0Srsmaeda *rsize = size; 3461d4b38e0Srsmaeda } 3471d4b38e0Srsmaeda return (0); 3481d4b38e0Srsmaeda } 3491d4b38e0Srsmaeda 3501d4b38e0Srsmaeda bufp = pack_message(cmd, flags, count, (void *)res, &size); 3511d4b38e0Srsmaeda DR_DBG_CTL("%s: from pack_message, bufp = %p size %ld\n", 3521d4b38e0Srsmaeda me, (void *)bufp, size); 3531d4b38e0Srsmaeda if (bufp == NULL || size == 0) 3541d4b38e0Srsmaeda return (EIO); 3551d4b38e0Srsmaeda 3561d4b38e0Srsmaeda rv = send_message(bufp, size, (void **)rbuf, rsize); 3571d4b38e0Srsmaeda 3581d4b38e0Srsmaeda /* 3591d4b38e0Srsmaeda * For failure, as part of our contract with the caller, 3601d4b38e0Srsmaeda * generate a response message, but mark all proposed 3611d4b38e0Srsmaeda * changes as 'denied'. 3621d4b38e0Srsmaeda */ 3631d4b38e0Srsmaeda if (rv != 0) { 3641d4b38e0Srsmaeda *rbuf = drctl_generate_resp(res, count, &size, 3651d4b38e0Srsmaeda DRCTL_STATUS_DENY); 3661d4b38e0Srsmaeda *rsize = size; 3671d4b38e0Srsmaeda } 3681d4b38e0Srsmaeda 3691d4b38e0Srsmaeda return (rv); 3701d4b38e0Srsmaeda } 3711d4b38e0Srsmaeda 3721d4b38e0Srsmaeda /* 3731d4b38e0Srsmaeda * Since the response comes from userland, make sure it is 3741d4b38e0Srsmaeda * at least the minimum size and, if it contains error 3751d4b38e0Srsmaeda * strings, that the string area is null-terminated. 3761d4b38e0Srsmaeda */ 3771d4b38e0Srsmaeda static int 3781d4b38e0Srsmaeda verify_response(int count, drctl_rsrc_t *resp, size_t size) 3791d4b38e0Srsmaeda { 3801d4b38e0Srsmaeda int idx; 3811d4b38e0Srsmaeda int need_terminator = 0; 3821d4b38e0Srsmaeda static const char me[] = "verify_response"; 3831d4b38e0Srsmaeda 3841d4b38e0Srsmaeda if (resp == NULL || size < count * sizeof (*resp)) { 3851d4b38e0Srsmaeda DR_DBG_CTL("%s: BAD size - count %d size %ld\n", 3861d4b38e0Srsmaeda me, count, size); 3871d4b38e0Srsmaeda return (EIO); 3881d4b38e0Srsmaeda } 3891d4b38e0Srsmaeda 3901d4b38e0Srsmaeda for (idx = 0; idx < count; idx++) { 3911d4b38e0Srsmaeda 3921d4b38e0Srsmaeda if (resp[idx].offset != 0) 3931d4b38e0Srsmaeda need_terminator++; 3941d4b38e0Srsmaeda } 3951d4b38e0Srsmaeda 3961d4b38e0Srsmaeda if (need_terminator && *((caddr_t)(resp) + size - 1) != '\0') { 3971d4b38e0Srsmaeda DR_DBG_CTL("%s: unterm. strings: resp %p size %ld char %d\n", 3981d4b38e0Srsmaeda me, (void *)resp, size, *((caddr_t)(resp) + size - 1)); 3991d4b38e0Srsmaeda /* Don't fail the transaction, but don't advertise strings */ 4001d4b38e0Srsmaeda for (idx = 0; idx < count; idx++) 4011d4b38e0Srsmaeda resp[idx].offset = 0; 4021d4b38e0Srsmaeda } 4031d4b38e0Srsmaeda 4041d4b38e0Srsmaeda return (0); 4051d4b38e0Srsmaeda } 4061d4b38e0Srsmaeda 4071d4b38e0Srsmaeda 4081d4b38e0Srsmaeda /* 4091d4b38e0Srsmaeda * Prepare for a reconfig operation. 4101d4b38e0Srsmaeda */ 4111d4b38e0Srsmaeda int 4121d4b38e0Srsmaeda drctl_config_init(int cmd, int flags, drctl_rsrc_t *res, 4131d4b38e0Srsmaeda int count, drctl_rsrc_t **rbuf, size_t *rsize, drctl_cookie_t ck) 4141d4b38e0Srsmaeda { 4151d4b38e0Srsmaeda static char me[] = "drctl_config_init"; 4161d4b38e0Srsmaeda int idx; 4171d4b38e0Srsmaeda int rv; 4181d4b38e0Srsmaeda 4191d4b38e0Srsmaeda if (ck == 0) 4201d4b38e0Srsmaeda return (EINVAL); 4211d4b38e0Srsmaeda 4221d4b38e0Srsmaeda mutex_enter(&drctlp->drc_lock); 4231d4b38e0Srsmaeda 4241d4b38e0Srsmaeda if (drctlp->drc_busy != NULL) { 4251d4b38e0Srsmaeda mutex_exit(&drctlp->drc_lock); 4261d4b38e0Srsmaeda return (EBUSY); 4271d4b38e0Srsmaeda } 4281d4b38e0Srsmaeda 4291d4b38e0Srsmaeda DR_DBG_CTL("%s: cmd %d flags %d res %p count %d\n", 4301d4b38e0Srsmaeda me, cmd, flags, (void *)res, count); 4311d4b38e0Srsmaeda 4321d4b38e0Srsmaeda /* Mark the link busy. Below we will fill in the actual cookie. */ 4331d4b38e0Srsmaeda drctlp->drc_busy = (drctl_cookie_t)-1; 4341d4b38e0Srsmaeda mutex_exit(&drctlp->drc_lock); 4351d4b38e0Srsmaeda 4361d4b38e0Srsmaeda if ((rv = drctl_config_common(cmd, 4371d4b38e0Srsmaeda flags, res, count, rbuf, rsize)) == 0 && 4381d4b38e0Srsmaeda verify_response(count, *rbuf, *rsize) == 0) { 4391d4b38e0Srsmaeda drctlp->drc_busy = ck; 4401d4b38e0Srsmaeda drctlp->drc_cmd = cmd; 4411d4b38e0Srsmaeda drctlp->drc_flags = flags; 4421d4b38e0Srsmaeda 4431d4b38e0Srsmaeda /* 4441d4b38e0Srsmaeda * If there wasn't a valid response msg passed back, 4451d4b38e0Srsmaeda * create a response with each resource op denied. 4461d4b38e0Srsmaeda */ 4471d4b38e0Srsmaeda if (*rbuf == NULL || *rsize == 0) { 4481d4b38e0Srsmaeda drctl_rsrc_t *bp = *rbuf; 4491d4b38e0Srsmaeda 4501d4b38e0Srsmaeda *rsize = count * sizeof (*bp); 4511d4b38e0Srsmaeda bp = kmem_zalloc(*rsize, KM_SLEEP); 4521d4b38e0Srsmaeda bcopy(res, bp, *rsize); 4531d4b38e0Srsmaeda 4541d4b38e0Srsmaeda for (idx = 0; idx < count; idx++) { 4551d4b38e0Srsmaeda bp[idx].status = DRCTL_STATUS_DENY; 4561d4b38e0Srsmaeda bp[idx].offset = 0; 4571d4b38e0Srsmaeda } 4581d4b38e0Srsmaeda } 4591d4b38e0Srsmaeda } else { 4601d4b38e0Srsmaeda drctlp->drc_cmd = -1; 4611d4b38e0Srsmaeda drctlp->drc_flags = 0; 4621d4b38e0Srsmaeda drctlp->drc_busy = NULL; 4631d4b38e0Srsmaeda } 4641d4b38e0Srsmaeda 4651d4b38e0Srsmaeda return (rv); 4661d4b38e0Srsmaeda } 4671d4b38e0Srsmaeda 4681d4b38e0Srsmaeda /* 4691d4b38e0Srsmaeda * Complete a reconfig operation. 4701d4b38e0Srsmaeda */ 4711d4b38e0Srsmaeda int 4721d4b38e0Srsmaeda drctl_config_fini(drctl_cookie_t ck, drctl_rsrc_t *res, int count) 4731d4b38e0Srsmaeda { 4741d4b38e0Srsmaeda int rv; 4751d4b38e0Srsmaeda int notify_cmd; 4761d4b38e0Srsmaeda int flags; 4771d4b38e0Srsmaeda 4781d4b38e0Srsmaeda mutex_enter(&drctlp->drc_lock); 4791d4b38e0Srsmaeda 4801d4b38e0Srsmaeda if (drctlp->drc_busy != ck) { 4811d4b38e0Srsmaeda mutex_exit(&drctlp->drc_lock); 4821d4b38e0Srsmaeda return (EBUSY); 4831d4b38e0Srsmaeda } 4841d4b38e0Srsmaeda 4851d4b38e0Srsmaeda mutex_exit(&drctlp->drc_lock); 4861d4b38e0Srsmaeda 4871d4b38e0Srsmaeda flags = drctlp->drc_flags; 4881d4b38e0Srsmaeda /* 4891d4b38e0Srsmaeda * Flip the saved _REQUEST command to its corresponding 4901d4b38e0Srsmaeda * _NOTIFY command. 4911d4b38e0Srsmaeda */ 4921d4b38e0Srsmaeda switch (drctlp->drc_cmd) { 4931d4b38e0Srsmaeda case DRCTL_CPU_CONFIG_REQUEST: 4941d4b38e0Srsmaeda notify_cmd = DRCTL_CPU_CONFIG_NOTIFY; 4951d4b38e0Srsmaeda break; 4961d4b38e0Srsmaeda 4971d4b38e0Srsmaeda case DRCTL_CPU_UNCONFIG_REQUEST: 4981d4b38e0Srsmaeda notify_cmd = DRCTL_CPU_UNCONFIG_NOTIFY; 4991d4b38e0Srsmaeda break; 5001d4b38e0Srsmaeda 5011d4b38e0Srsmaeda case DRCTL_MEM_CONFIG_REQUEST: 5021d4b38e0Srsmaeda case DRCTL_MEM_CONFIG_NOTIFY: 5031d4b38e0Srsmaeda case DRCTL_MEM_UNCONFIG_REQUEST: 5041d4b38e0Srsmaeda case DRCTL_MEM_UNCONFIG_NOTIFY: 5051d4b38e0Srsmaeda case DRCTL_IO_CONFIG_REQUEST: 5061d4b38e0Srsmaeda case DRCTL_IO_CONFIG_NOTIFY: 5071d4b38e0Srsmaeda case DRCTL_IO_UNCONFIG_REQUEST: 5081d4b38e0Srsmaeda case DRCTL_IO_UNCONFIG_NOTIFY: 5091d4b38e0Srsmaeda default: 5101d4b38e0Srsmaeda /* none of the above should have been accepted in _init */ 5111d4b38e0Srsmaeda ASSERT(0); 5121d4b38e0Srsmaeda cmn_err(CE_CONT, 5131d4b38e0Srsmaeda "drctl_config_fini: bad cmd %d\n", drctlp->drc_cmd); 5141d4b38e0Srsmaeda rv = EINVAL; 5151d4b38e0Srsmaeda goto done; 5161d4b38e0Srsmaeda } 5171d4b38e0Srsmaeda 5181d4b38e0Srsmaeda rv = drctl_config_common(notify_cmd, flags, res, count, NULL, 0); 5191d4b38e0Srsmaeda 5201d4b38e0Srsmaeda done: 5211d4b38e0Srsmaeda drctlp->drc_cmd = -1; 5221d4b38e0Srsmaeda drctlp->drc_flags = 0; 5231d4b38e0Srsmaeda drctlp->drc_busy = NULL; 5241d4b38e0Srsmaeda 5251d4b38e0Srsmaeda return (rv); 5261d4b38e0Srsmaeda } 5271d4b38e0Srsmaeda 5281d4b38e0Srsmaeda static int 5291d4b38e0Srsmaeda drctl_ioctl(dev_t dev, 5301d4b38e0Srsmaeda int cmd, intptr_t arg, int mode, cred_t *cred_p, int *rval_p) 5311d4b38e0Srsmaeda { 5321d4b38e0Srsmaeda _NOTE(ARGUNUSED(dev, mode, cred_p, rval_p)) 5331d4b38e0Srsmaeda 5341d4b38e0Srsmaeda int rv; 5351d4b38e0Srsmaeda 5361d4b38e0Srsmaeda switch (cmd) { 5371d4b38e0Srsmaeda case DRCTL_IOCTL_CONNECT_SERVER: 5381d4b38e0Srsmaeda rv = i_drctl_ioctl(cmd, arg); 5391d4b38e0Srsmaeda break; 5401d4b38e0Srsmaeda default: 5411d4b38e0Srsmaeda rv = ENOTSUP; 5421d4b38e0Srsmaeda } 5431d4b38e0Srsmaeda 5441d4b38e0Srsmaeda *rval_p = (rv == 0) ? 0 : -1; 5451d4b38e0Srsmaeda 5461d4b38e0Srsmaeda return (rv); 5471d4b38e0Srsmaeda } 5481d4b38e0Srsmaeda 5491d4b38e0Srsmaeda /* 5501d4b38e0Srsmaeda * Accept a preformatted request from caller and send a message to 5511d4b38e0Srsmaeda * the daemon. A pointer to the daemon's response buffer is passed 5521d4b38e0Srsmaeda * back in obufp, its size in osize. 5531d4b38e0Srsmaeda */ 5541d4b38e0Srsmaeda static int 5551d4b38e0Srsmaeda send_message(void *msg, size_t size, void **obufp, size_t *osize) 5561d4b38e0Srsmaeda { 5571d4b38e0Srsmaeda int rv; 5581d4b38e0Srsmaeda 5591d4b38e0Srsmaeda rv = i_drctl_send(msg, size, obufp, osize); 5601d4b38e0Srsmaeda 5611d4b38e0Srsmaeda kmem_free(msg, size); 5621d4b38e0Srsmaeda 5631d4b38e0Srsmaeda return (rv); 5641d4b38e0Srsmaeda } 5651d4b38e0Srsmaeda 5661d4b38e0Srsmaeda static void * 5671d4b38e0Srsmaeda pack_message(int cmd, int flags, int count, void *data, size_t *osize) 5681d4b38e0Srsmaeda { 5691d4b38e0Srsmaeda drd_msg_t *msgp; 5701d4b38e0Srsmaeda size_t hdr_size = offsetof(drd_msg_t, data); 5711d4b38e0Srsmaeda 5721d4b38e0Srsmaeda switch (cmd) { 5731d4b38e0Srsmaeda case DRCTL_CPU_CONFIG_REQUEST: 5741d4b38e0Srsmaeda case DRCTL_CPU_CONFIG_NOTIFY: 5751d4b38e0Srsmaeda case DRCTL_CPU_UNCONFIG_REQUEST: 5761d4b38e0Srsmaeda case DRCTL_CPU_UNCONFIG_NOTIFY: 5771d4b38e0Srsmaeda 5781d4b38e0Srsmaeda *osize = hdr_size + count * sizeof (drctl_rsrc_t); 5791d4b38e0Srsmaeda 5801d4b38e0Srsmaeda msgp = kmem_alloc(*osize, KM_SLEEP); 5811d4b38e0Srsmaeda msgp->cmd = cmd; 5821d4b38e0Srsmaeda msgp->count = count; 5831d4b38e0Srsmaeda msgp->flags = flags; 5841d4b38e0Srsmaeda bcopy(data, msgp->data, count * sizeof (drctl_rsrc_t)); 5851d4b38e0Srsmaeda break; 5861d4b38e0Srsmaeda default: 5871d4b38e0Srsmaeda cmn_err(CE_WARN, 5881d4b38e0Srsmaeda "drctl: pack_message received invalid cmd %d", cmd); 5891d4b38e0Srsmaeda msgp = NULL; 5901d4b38e0Srsmaeda } 5911d4b38e0Srsmaeda 5921d4b38e0Srsmaeda return (msgp); 5931d4b38e0Srsmaeda } 594