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 /* 23*02b4e56cSHaik Aftandilian * Copyright (c) 2006, 2010, Oracle and/or its affiliates. All rights reserved. 241d4b38e0Srsmaeda */ 251d4b38e0Srsmaeda 261d4b38e0Srsmaeda /* 271d4b38e0Srsmaeda * DR control module for LDoms 281d4b38e0Srsmaeda */ 291d4b38e0Srsmaeda 301d4b38e0Srsmaeda #include <sys/sysmacros.h> 311d4b38e0Srsmaeda #include <sys/modctl.h> 321d4b38e0Srsmaeda #include <sys/conf.h> 331d4b38e0Srsmaeda #include <sys/ddi.h> 341d4b38e0Srsmaeda #include <sys/sunddi.h> 351d4b38e0Srsmaeda #include <sys/ddi_impldefs.h> 361d4b38e0Srsmaeda #include <sys/stat.h> 371d4b38e0Srsmaeda #include <sys/door.h> 381d4b38e0Srsmaeda #include <sys/open.h> 391d4b38e0Srsmaeda #include <sys/note.h> 401d4b38e0Srsmaeda #include <sys/ldoms.h> 411d4b38e0Srsmaeda #include <sys/dr_util.h> 421d4b38e0Srsmaeda #include <sys/drctl.h> 431d4b38e0Srsmaeda #include <sys/drctl_impl.h> 441d4b38e0Srsmaeda 451d4b38e0Srsmaeda 461d4b38e0Srsmaeda static int drctl_attach(dev_info_t *, ddi_attach_cmd_t); 471d4b38e0Srsmaeda static int drctl_detach(dev_info_t *, ddi_detach_cmd_t); 481d4b38e0Srsmaeda static int drctl_getinfo(dev_info_t *, ddi_info_cmd_t, void *, void **); 491d4b38e0Srsmaeda 501d4b38e0Srsmaeda static int drctl_open(dev_t *, int, int, cred_t *); 511d4b38e0Srsmaeda static int drctl_close(dev_t, int, int, cred_t *); 521d4b38e0Srsmaeda static int drctl_ioctl(dev_t, int, intptr_t, int, cred_t *, int *); 531d4b38e0Srsmaeda 5499c7e855SJames Marks - Sun Microsystems static void *pack_message(int, int, int, void *, size_t *, size_t *); 5599c7e855SJames Marks - Sun Microsystems static int send_message(void *, size_t, drctl_resp_t **, size_t *); 561d4b38e0Srsmaeda 571d4b38e0Srsmaeda 581d4b38e0Srsmaeda /* 591d4b38e0Srsmaeda * Configuration data structures 601d4b38e0Srsmaeda */ 611d4b38e0Srsmaeda static struct cb_ops drctl_cb_ops = { 621d4b38e0Srsmaeda drctl_open, /* open */ 631d4b38e0Srsmaeda drctl_close, /* close */ 641d4b38e0Srsmaeda nodev, /* strategy */ 651d4b38e0Srsmaeda nodev, /* print */ 661d4b38e0Srsmaeda nodev, /* dump */ 671d4b38e0Srsmaeda nodev, /* read */ 681d4b38e0Srsmaeda nodev, /* write */ 691d4b38e0Srsmaeda drctl_ioctl, /* ioctl */ 701d4b38e0Srsmaeda nodev, /* devmap */ 711d4b38e0Srsmaeda nodev, /* mmap */ 721d4b38e0Srsmaeda nodev, /* segmap */ 731d4b38e0Srsmaeda nochpoll, /* poll */ 741d4b38e0Srsmaeda ddi_prop_op, /* prop_op */ 751d4b38e0Srsmaeda NULL, /* streamtab */ 761d4b38e0Srsmaeda D_MP | D_NEW, /* driver compatibility flag */ 771d4b38e0Srsmaeda CB_REV, /* cb_ops revision */ 781d4b38e0Srsmaeda nodev, /* async read */ 791d4b38e0Srsmaeda nodev /* async write */ 801d4b38e0Srsmaeda }; 811d4b38e0Srsmaeda 821d4b38e0Srsmaeda 831d4b38e0Srsmaeda static struct dev_ops drctl_ops = { 841d4b38e0Srsmaeda DEVO_REV, /* devo_rev */ 851d4b38e0Srsmaeda 0, /* refcnt */ 861d4b38e0Srsmaeda drctl_getinfo, /* info */ 871d4b38e0Srsmaeda nulldev, /* identify */ 881d4b38e0Srsmaeda nulldev, /* probe */ 891d4b38e0Srsmaeda drctl_attach, /* attach */ 901d4b38e0Srsmaeda drctl_detach, /* detach */ 911d4b38e0Srsmaeda nodev, /* reset */ 921d4b38e0Srsmaeda &drctl_cb_ops, /* driver operations */ 931d4b38e0Srsmaeda NULL, /* bus operations */ 941d4b38e0Srsmaeda NULL, /* power */ 9519397407SSherry Moore ddi_quiesce_not_needed, /* quiesce */ 961d4b38e0Srsmaeda }; 971d4b38e0Srsmaeda 981d4b38e0Srsmaeda static struct modldrv modldrv = { 991d4b38e0Srsmaeda &mod_driverops, /* type of module - driver */ 10019397407SSherry Moore "DR Control pseudo driver", 1011d4b38e0Srsmaeda &drctl_ops 1021d4b38e0Srsmaeda }; 1031d4b38e0Srsmaeda 1041d4b38e0Srsmaeda static struct modlinkage modlinkage = { 1051d4b38e0Srsmaeda MODREV_1, 1061d4b38e0Srsmaeda &modldrv, 1071d4b38e0Srsmaeda NULL 1081d4b38e0Srsmaeda }; 1091d4b38e0Srsmaeda 1101d4b38e0Srsmaeda 1111d4b38e0Srsmaeda /* 1121d4b38e0Srsmaeda * Locking strategy 1131d4b38e0Srsmaeda * 1141d4b38e0Srsmaeda * One of the reasons for this module's existence is to serialize 1151d4b38e0Srsmaeda * DR requests which might be coming from different sources. Only 1161d4b38e0Srsmaeda * one operation is allowed to be in progress at any given time. 1171d4b38e0Srsmaeda * 1181d4b38e0Srsmaeda * A single lock word (the 'drc_busy' element below) is NULL 1191d4b38e0Srsmaeda * when there is no operation in progress. When a client of this 1201d4b38e0Srsmaeda * module initiates an operation it grabs the mutex 'drc_lock' in 1211d4b38e0Srsmaeda * order to examine the lock word ('drc_busy'). If no other 1221d4b38e0Srsmaeda * operation is in progress, the lock word will be NULL. If so, 1231d4b38e0Srsmaeda * a cookie which uniquely identifies the requestor is stored in 1241d4b38e0Srsmaeda * the lock word, and the mutex is released. Attempts by other 1251d4b38e0Srsmaeda * clients to initiate an operation will fail. 1261d4b38e0Srsmaeda * 1271d4b38e0Srsmaeda * When the lock-holding client's operation is completed, the 1281d4b38e0Srsmaeda * client will call a "finalize" function in this module, providing 1291d4b38e0Srsmaeda * the cookie passed with the original request. Since the cookie 1301d4b38e0Srsmaeda * matches, the operation will succeed and the lock word will be 1311d4b38e0Srsmaeda * cleared. At this point, an new operation may be initiated. 1321d4b38e0Srsmaeda */ 1331d4b38e0Srsmaeda 1341d4b38e0Srsmaeda /* 1351d4b38e0Srsmaeda * Driver private data 1361d4b38e0Srsmaeda */ 1371d4b38e0Srsmaeda static struct drctl_unit { 1381d4b38e0Srsmaeda kmutex_t drc_lock; /* global driver lock */ 1391d4b38e0Srsmaeda dev_info_t *drc_dip; /* dev_info pointer */ 1401d4b38e0Srsmaeda kcondvar_t drc_busy_cv; /* block for !busy */ 1411d4b38e0Srsmaeda drctl_cookie_t drc_busy; /* NULL if free else a unique */ 1421d4b38e0Srsmaeda /* identifier for caller */ 1431d4b38e0Srsmaeda int drc_cmd; /* the cmd underway (or -1) */ 1441d4b38e0Srsmaeda int drc_flags; /* saved flag from above cmd */ 1451d4b38e0Srsmaeda int drc_inst; /* our single instance */ 1461d4b38e0Srsmaeda uint_t drc_state; /* driver state */ 1471d4b38e0Srsmaeda } drctl_state; 1481d4b38e0Srsmaeda 1491d4b38e0Srsmaeda static struct drctl_unit *drctlp = &drctl_state; 1501d4b38e0Srsmaeda 1511d4b38e0Srsmaeda int 1521d4b38e0Srsmaeda _init(void) 1531d4b38e0Srsmaeda { 154e1ebb9ecSlm66018 int rv; 155e1ebb9ecSlm66018 1561d4b38e0Srsmaeda drctlp->drc_inst = -1; 1571d4b38e0Srsmaeda mutex_init(&drctlp->drc_lock, NULL, MUTEX_DRIVER, NULL); 158af4c679fSSean McEnroe cv_init(&drctlp->drc_busy_cv, NULL, CV_DRIVER, NULL); 159e1ebb9ecSlm66018 160e1ebb9ecSlm66018 if ((rv = mod_install(&modlinkage)) != 0) 161e1ebb9ecSlm66018 mutex_destroy(&drctlp->drc_lock); 162e1ebb9ecSlm66018 163e1ebb9ecSlm66018 return (rv); 1641d4b38e0Srsmaeda } 1651d4b38e0Srsmaeda 1661d4b38e0Srsmaeda 1671d4b38e0Srsmaeda int 1681d4b38e0Srsmaeda _fini(void) 1691d4b38e0Srsmaeda { 170e1ebb9ecSlm66018 int rv; 171e1ebb9ecSlm66018 172e1ebb9ecSlm66018 if ((rv = mod_remove(&modlinkage)) != 0) 173e1ebb9ecSlm66018 return (rv); 174af4c679fSSean McEnroe cv_destroy(&drctlp->drc_busy_cv); 1751d4b38e0Srsmaeda mutex_destroy(&drctlp->drc_lock); 176e1ebb9ecSlm66018 return (0); 1771d4b38e0Srsmaeda } 1781d4b38e0Srsmaeda 1791d4b38e0Srsmaeda 1801d4b38e0Srsmaeda int 1811d4b38e0Srsmaeda _info(struct modinfo *modinfop) 1821d4b38e0Srsmaeda { 1831d4b38e0Srsmaeda return (mod_info(&modlinkage, modinfop)); 1841d4b38e0Srsmaeda } 1851d4b38e0Srsmaeda 1861d4b38e0Srsmaeda 1871d4b38e0Srsmaeda /* 1881d4b38e0Srsmaeda * Do the attach work 1891d4b38e0Srsmaeda */ 1901d4b38e0Srsmaeda static int 1911d4b38e0Srsmaeda drctl_do_attach(dev_info_t *dip, ddi_attach_cmd_t cmd) 1921d4b38e0Srsmaeda { 1931d4b38e0Srsmaeda _NOTE(ARGUNUSED(cmd)) 1941d4b38e0Srsmaeda 1951d4b38e0Srsmaeda char *str = "drctl_do_attach"; 1961d4b38e0Srsmaeda int retval = DDI_SUCCESS; 1971d4b38e0Srsmaeda 1981d4b38e0Srsmaeda if (drctlp->drc_inst != -1) { 1991d4b38e0Srsmaeda cmn_err(CE_WARN, "%s: an instance is already attached!", str); 2001d4b38e0Srsmaeda return (DDI_FAILURE); 2011d4b38e0Srsmaeda } 2021d4b38e0Srsmaeda drctlp->drc_inst = ddi_get_instance(dip); 2031d4b38e0Srsmaeda 2041d4b38e0Srsmaeda retval = ddi_create_minor_node(dip, "drctl", S_IFCHR, 2051d4b38e0Srsmaeda drctlp->drc_inst, DDI_PSEUDO, 0); 2061d4b38e0Srsmaeda if (retval != DDI_SUCCESS) { 2071d4b38e0Srsmaeda cmn_err(CE_WARN, "%s: can't create minor node", str); 2081d4b38e0Srsmaeda drctlp->drc_inst = -1; 2091d4b38e0Srsmaeda return (retval); 2101d4b38e0Srsmaeda } 2111d4b38e0Srsmaeda 2121d4b38e0Srsmaeda drctlp->drc_dip = dip; 2131d4b38e0Srsmaeda ddi_report_dev(dip); 2141d4b38e0Srsmaeda 2151d4b38e0Srsmaeda return (retval); 2161d4b38e0Srsmaeda } 2171d4b38e0Srsmaeda 2181d4b38e0Srsmaeda 2191d4b38e0Srsmaeda static int 2201d4b38e0Srsmaeda drctl_attach(dev_info_t *dip, ddi_attach_cmd_t cmd) 2211d4b38e0Srsmaeda { 2221d4b38e0Srsmaeda switch (cmd) { 2231d4b38e0Srsmaeda case DDI_ATTACH: 2241d4b38e0Srsmaeda return (drctl_do_attach(dip, cmd)); 2251d4b38e0Srsmaeda 2261d4b38e0Srsmaeda default: 2271d4b38e0Srsmaeda return (DDI_FAILURE); 2281d4b38e0Srsmaeda } 2291d4b38e0Srsmaeda } 2301d4b38e0Srsmaeda 2311d4b38e0Srsmaeda 2321d4b38e0Srsmaeda /* ARGSUSED */ 2331d4b38e0Srsmaeda static int 2341d4b38e0Srsmaeda drctl_detach(dev_info_t *dip, ddi_detach_cmd_t cmd) 2351d4b38e0Srsmaeda { 2361d4b38e0Srsmaeda switch (cmd) { 2371d4b38e0Srsmaeda case DDI_DETACH: 2381d4b38e0Srsmaeda drctlp->drc_inst = -1; 2391d4b38e0Srsmaeda ddi_remove_minor_node(dip, "drctl"); 2401d4b38e0Srsmaeda return (DDI_SUCCESS); 2411d4b38e0Srsmaeda 2421d4b38e0Srsmaeda default: 2431d4b38e0Srsmaeda return (DDI_FAILURE); 2441d4b38e0Srsmaeda } 2451d4b38e0Srsmaeda } 2461d4b38e0Srsmaeda 2471d4b38e0Srsmaeda static int 2481d4b38e0Srsmaeda drctl_getinfo(dev_info_t *dip, ddi_info_cmd_t cmd, void *arg, void **resultp) 2491d4b38e0Srsmaeda { 2501d4b38e0Srsmaeda _NOTE(ARGUNUSED(dip, cmd, arg, resultp)) 2511d4b38e0Srsmaeda 2521d4b38e0Srsmaeda return (0); 2531d4b38e0Srsmaeda } 2541d4b38e0Srsmaeda 2551d4b38e0Srsmaeda static int 2561d4b38e0Srsmaeda drctl_open(dev_t *devp, int flag, int otyp, cred_t *cred_p) 2571d4b38e0Srsmaeda { 2581d4b38e0Srsmaeda _NOTE(ARGUNUSED(devp, flag, cred_p)) 2591d4b38e0Srsmaeda 2601d4b38e0Srsmaeda if (otyp != OTYP_CHR) 2611d4b38e0Srsmaeda return (EINVAL); 2621d4b38e0Srsmaeda 2631d4b38e0Srsmaeda return (0); 2641d4b38e0Srsmaeda } 2651d4b38e0Srsmaeda 2661d4b38e0Srsmaeda static int 2671d4b38e0Srsmaeda drctl_close(dev_t dev, int flag, int otyp, cred_t *cred_p) 2681d4b38e0Srsmaeda { 2691d4b38e0Srsmaeda _NOTE(ARGUNUSED(dev, flag, otyp, cred_p)) 2701d4b38e0Srsmaeda 2711d4b38e0Srsmaeda return (0); 2721d4b38e0Srsmaeda } 2731d4b38e0Srsmaeda 2741d4b38e0Srsmaeda /* 27599c7e855SJames Marks - Sun Microsystems * Create a reponse structure which includes an array of drctl_rsrc_t 27699c7e855SJames Marks - Sun Microsystems * structures in which each status element is set to the 'status' 27799c7e855SJames Marks - Sun Microsystems * arg. There is no error text, so set the 'offset' elements to 0. 2781d4b38e0Srsmaeda */ 27999c7e855SJames Marks - Sun Microsystems static drctl_resp_t * 2801d4b38e0Srsmaeda drctl_generate_resp(drctl_rsrc_t *res, 2811d4b38e0Srsmaeda int count, size_t *rsize, drctl_status_t status) 2821d4b38e0Srsmaeda { 28399c7e855SJames Marks - Sun Microsystems int i; 2841d4b38e0Srsmaeda size_t size; 28599c7e855SJames Marks - Sun Microsystems drctl_rsrc_t *rsrc; 28699c7e855SJames Marks - Sun Microsystems drctl_resp_t *resp; 2871d4b38e0Srsmaeda 28899c7e855SJames Marks - Sun Microsystems size = offsetof(drctl_resp_t, resp_resources) + (count * sizeof (*res)); 28999c7e855SJames Marks - Sun Microsystems resp = kmem_alloc(size, KM_SLEEP); 29099c7e855SJames Marks - Sun Microsystems DR_DBG_KMEM("%s: alloc addr %p size %ld\n", 29199c7e855SJames Marks - Sun Microsystems __func__, (void *)resp, size); 2921d4b38e0Srsmaeda 29399c7e855SJames Marks - Sun Microsystems resp->resp_type = DRCTL_RESP_OK; 29499c7e855SJames Marks - Sun Microsystems rsrc = resp->resp_resources; 2951d4b38e0Srsmaeda 29699c7e855SJames Marks - Sun Microsystems bcopy(res, rsrc, count * sizeof (*res)); 29799c7e855SJames Marks - Sun Microsystems 29899c7e855SJames Marks - Sun Microsystems for (i = 0; i < count; i++) { 29999c7e855SJames Marks - Sun Microsystems rsrc[i].status = status; 30099c7e855SJames Marks - Sun Microsystems rsrc[i].offset = 0; 3011d4b38e0Srsmaeda } 3021d4b38e0Srsmaeda 3031d4b38e0Srsmaeda *rsize = size; 30499c7e855SJames Marks - Sun Microsystems 30599c7e855SJames Marks - Sun Microsystems return (resp); 3061d4b38e0Srsmaeda } 3071d4b38e0Srsmaeda 30899c7e855SJames Marks - Sun Microsystems /* 30999c7e855SJames Marks - Sun Microsystems * Generate an error response message. 31099c7e855SJames Marks - Sun Microsystems */ 31199c7e855SJames Marks - Sun Microsystems static drctl_resp_t * 31299c7e855SJames Marks - Sun Microsystems drctl_generate_err_resp(char *msg, size_t *size) 31399c7e855SJames Marks - Sun Microsystems { 31499c7e855SJames Marks - Sun Microsystems drctl_resp_t *resp; 31599c7e855SJames Marks - Sun Microsystems 31699c7e855SJames Marks - Sun Microsystems ASSERT(msg != NULL); 31799c7e855SJames Marks - Sun Microsystems ASSERT(size != NULL); 31899c7e855SJames Marks - Sun Microsystems 31999c7e855SJames Marks - Sun Microsystems *size = offsetof(drctl_resp_t, resp_err_msg) + strlen(msg) + 1; 32099c7e855SJames Marks - Sun Microsystems resp = kmem_alloc(*size, KM_SLEEP); 32199c7e855SJames Marks - Sun Microsystems DR_DBG_KMEM("%s: alloc addr %p size %ld\n", 32299c7e855SJames Marks - Sun Microsystems __func__, (void *)resp, *size); 32399c7e855SJames Marks - Sun Microsystems 32499c7e855SJames Marks - Sun Microsystems resp->resp_type = DRCTL_RESP_ERR; 32599c7e855SJames Marks - Sun Microsystems (void) strcpy(resp->resp_err_msg, msg); 32699c7e855SJames Marks - Sun Microsystems 32799c7e855SJames Marks - Sun Microsystems return (resp); 32899c7e855SJames Marks - Sun Microsystems } 32999c7e855SJames Marks - Sun Microsystems 33099c7e855SJames Marks - Sun Microsystems /* 33199c7e855SJames Marks - Sun Microsystems * Since response comes from userland, verify that it is at least the 33299c7e855SJames Marks - Sun Microsystems * minimum size based on the size of the original request. Verify 33399c7e855SJames Marks - Sun Microsystems * that any offsets to error strings are within the string area of 33499c7e855SJames Marks - Sun Microsystems * the response and, force the string area to be null-terminated. 33599c7e855SJames Marks - Sun Microsystems */ 33699c7e855SJames Marks - Sun Microsystems static int 33799c7e855SJames Marks - Sun Microsystems verify_response(int cmd, 33899c7e855SJames Marks - Sun Microsystems int count, drctl_resp_t *resp, size_t sent_len, size_t resp_len) 33999c7e855SJames Marks - Sun Microsystems { 34099c7e855SJames Marks - Sun Microsystems drctl_rsrc_t *rsrc = resp->resp_resources; 34199c7e855SJames Marks - Sun Microsystems size_t rcvd_len = resp_len - (offsetof(drctl_resp_t, resp_resources)); 34299c7e855SJames Marks - Sun Microsystems int is_cpu = 0; 34399c7e855SJames Marks - Sun Microsystems int i; 34499c7e855SJames Marks - Sun Microsystems 34599c7e855SJames Marks - Sun Microsystems switch (cmd) { 34699c7e855SJames Marks - Sun Microsystems case DRCTL_CPU_CONFIG_REQUEST: 34799c7e855SJames Marks - Sun Microsystems case DRCTL_CPU_UNCONFIG_REQUEST: 34899c7e855SJames Marks - Sun Microsystems if (rcvd_len < sent_len) 34999c7e855SJames Marks - Sun Microsystems return (EIO); 35099c7e855SJames Marks - Sun Microsystems is_cpu = 1; 35199c7e855SJames Marks - Sun Microsystems break; 35299c7e855SJames Marks - Sun Microsystems case DRCTL_IO_UNCONFIG_REQUEST: 35399c7e855SJames Marks - Sun Microsystems case DRCTL_IO_CONFIG_REQUEST: 35499c7e855SJames Marks - Sun Microsystems if (count != 1) 35599c7e855SJames Marks - Sun Microsystems return (EIO); 35699c7e855SJames Marks - Sun Microsystems break; 3579853d9e8SJason Beloro case DRCTL_MEM_CONFIG_REQUEST: 3589853d9e8SJason Beloro case DRCTL_MEM_UNCONFIG_REQUEST: 3599853d9e8SJason Beloro break; 36099c7e855SJames Marks - Sun Microsystems default: 36199c7e855SJames Marks - Sun Microsystems return (EIO); 36299c7e855SJames Marks - Sun Microsystems } 36399c7e855SJames Marks - Sun Microsystems 36499c7e855SJames Marks - Sun Microsystems for (i = 0; i < count; i++) 36599c7e855SJames Marks - Sun Microsystems if ((rsrc[i].offset > 0) && 36699c7e855SJames Marks - Sun Microsystems /* string can't be inside the bounds of original request */ 36799c7e855SJames Marks - Sun Microsystems (((rsrc[i].offset < sent_len) && is_cpu) || 36899c7e855SJames Marks - Sun Microsystems /* string must start inside the message */ 36999c7e855SJames Marks - Sun Microsystems (rsrc[i].offset >= rcvd_len))) 37099c7e855SJames Marks - Sun Microsystems return (EIO); 37199c7e855SJames Marks - Sun Microsystems 37299c7e855SJames Marks - Sun Microsystems /* If there are any strings, terminate the string area. */ 37399c7e855SJames Marks - Sun Microsystems if (rcvd_len > sent_len) 37499c7e855SJames Marks - Sun Microsystems *((char *)rsrc + rcvd_len - 1) = '\0'; 37599c7e855SJames Marks - Sun Microsystems 37699c7e855SJames Marks - Sun Microsystems return (0); 37799c7e855SJames Marks - Sun Microsystems } 37899c7e855SJames Marks - Sun Microsystems 3791d4b38e0Srsmaeda static int 3801d4b38e0Srsmaeda drctl_config_common(int cmd, int flags, drctl_rsrc_t *res, 38199c7e855SJames Marks - Sun Microsystems int count, drctl_resp_t **rbuf, size_t *rsize, size_t *rq_size) 3821d4b38e0Srsmaeda { 3831d4b38e0Srsmaeda int rv = 0; 3841d4b38e0Srsmaeda size_t size; 3851d4b38e0Srsmaeda char *bufp; 3861d4b38e0Srsmaeda 3871d4b38e0Srsmaeda switch (cmd) { 3881d4b38e0Srsmaeda case DRCTL_CPU_CONFIG_REQUEST: 3891d4b38e0Srsmaeda case DRCTL_CPU_CONFIG_NOTIFY: 3901d4b38e0Srsmaeda case DRCTL_CPU_UNCONFIG_REQUEST: 3911d4b38e0Srsmaeda case DRCTL_CPU_UNCONFIG_NOTIFY: 3928fea755aSjm22469 case DRCTL_IO_UNCONFIG_REQUEST: 3938fea755aSjm22469 case DRCTL_IO_UNCONFIG_NOTIFY: 3948fea755aSjm22469 case DRCTL_IO_CONFIG_REQUEST: 3958fea755aSjm22469 case DRCTL_IO_CONFIG_NOTIFY: 3961d4b38e0Srsmaeda case DRCTL_MEM_CONFIG_REQUEST: 3971d4b38e0Srsmaeda case DRCTL_MEM_CONFIG_NOTIFY: 3981d4b38e0Srsmaeda case DRCTL_MEM_UNCONFIG_REQUEST: 3991d4b38e0Srsmaeda case DRCTL_MEM_UNCONFIG_NOTIFY: 4009853d9e8SJason Beloro rv = 0; 4019853d9e8SJason Beloro break; 4029853d9e8SJason Beloro default: 4031d4b38e0Srsmaeda rv = ENOTSUP; 4041d4b38e0Srsmaeda break; 4051d4b38e0Srsmaeda } 4061d4b38e0Srsmaeda 4071d4b38e0Srsmaeda if (rv != 0) { 40899c7e855SJames Marks - Sun Microsystems DR_DBG_CTL("%s: invalid cmd %d\n", __func__, cmd); 4091d4b38e0Srsmaeda return (rv); 4101d4b38e0Srsmaeda } 4111d4b38e0Srsmaeda 4121d4b38e0Srsmaeda /* 4131d4b38e0Srsmaeda * If the operation is a FORCE, we don't send a message to 4141d4b38e0Srsmaeda * the daemon. But, the upstream clients still expect a 4151d4b38e0Srsmaeda * response, so generate a response with all ops 'allowed'. 4161d4b38e0Srsmaeda */ 4171d4b38e0Srsmaeda if (flags == DRCTL_FLAG_FORCE) { 41899c7e855SJames Marks - Sun Microsystems if (rbuf != NULL) 41999c7e855SJames Marks - Sun Microsystems *rbuf = drctl_generate_resp(res, 42099c7e855SJames Marks - Sun Microsystems count, rsize, DRCTL_STATUS_ALLOW); 4211d4b38e0Srsmaeda return (0); 4221d4b38e0Srsmaeda } 4231d4b38e0Srsmaeda 42499c7e855SJames Marks - Sun Microsystems bufp = pack_message(cmd, flags, count, (void *)res, &size, rq_size); 4251d4b38e0Srsmaeda DR_DBG_CTL("%s: from pack_message, bufp = %p size %ld\n", 42699c7e855SJames Marks - Sun Microsystems __func__, (void *)bufp, size); 42799c7e855SJames Marks - Sun Microsystems 4281d4b38e0Srsmaeda if (bufp == NULL || size == 0) 42999c7e855SJames Marks - Sun Microsystems return (EINVAL); 4301d4b38e0Srsmaeda 43199c7e855SJames Marks - Sun Microsystems return (send_message(bufp, size, rbuf, rsize)); 4321d4b38e0Srsmaeda } 4331d4b38e0Srsmaeda 4341d4b38e0Srsmaeda /* 4351d4b38e0Srsmaeda * Prepare for a reconfig operation. 4361d4b38e0Srsmaeda */ 4371d4b38e0Srsmaeda int 4381d4b38e0Srsmaeda drctl_config_init(int cmd, int flags, drctl_rsrc_t *res, 43999c7e855SJames Marks - Sun Microsystems int count, drctl_resp_t **rbuf, size_t *rsize, drctl_cookie_t ck) 4401d4b38e0Srsmaeda { 44199c7e855SJames Marks - Sun Microsystems static char inval_msg[] = "Invalid command format received.\n"; 44299c7e855SJames Marks - Sun Microsystems static char unsup_msg[] = "Unsuppported command received.\n"; 44399c7e855SJames Marks - Sun Microsystems static char unk_msg [] = "Failure reason unknown.\n"; 44499c7e855SJames Marks - Sun Microsystems static char rsp_msg [] = "Invalid response from " 44599c7e855SJames Marks - Sun Microsystems "reconfiguration daemon.\n"; 44699c7e855SJames Marks - Sun Microsystems static char drd_msg [] = "Cannot communicate with reconfiguration " 44799c7e855SJames Marks - Sun Microsystems "daemon (drd) in target domain.\n" 44899c7e855SJames Marks - Sun Microsystems "drd(1M) SMF service may not be enabled.\n"; 44999c7e855SJames Marks - Sun Microsystems static char busy_msg [] = "Busy executing earlier command; " 45099c7e855SJames Marks - Sun Microsystems "please try again later.\n"; 45199c7e855SJames Marks - Sun Microsystems size_t rq_size; 45299c7e855SJames Marks - Sun Microsystems char *ermsg; 4531d4b38e0Srsmaeda int rv; 4541d4b38e0Srsmaeda 45599c7e855SJames Marks - Sun Microsystems if (ck == 0) { 45699c7e855SJames Marks - Sun Microsystems *rbuf = drctl_generate_err_resp(inval_msg, rsize); 45799c7e855SJames Marks - Sun Microsystems 4581d4b38e0Srsmaeda return (EINVAL); 45999c7e855SJames Marks - Sun Microsystems } 4601d4b38e0Srsmaeda 4611d4b38e0Srsmaeda mutex_enter(&drctlp->drc_lock); 4621d4b38e0Srsmaeda if (drctlp->drc_busy != NULL) { 4631d4b38e0Srsmaeda mutex_exit(&drctlp->drc_lock); 46499c7e855SJames Marks - Sun Microsystems *rbuf = drctl_generate_err_resp(busy_msg, rsize); 46599c7e855SJames Marks - Sun Microsystems 4661d4b38e0Srsmaeda return (EBUSY); 4671d4b38e0Srsmaeda } 4681d4b38e0Srsmaeda 4691d4b38e0Srsmaeda DR_DBG_CTL("%s: cmd %d flags %d res %p count %d\n", 47099c7e855SJames Marks - Sun Microsystems __func__, cmd, flags, (void *)res, count); 4711d4b38e0Srsmaeda 4721d4b38e0Srsmaeda /* Mark the link busy. Below we will fill in the actual cookie. */ 4731d4b38e0Srsmaeda drctlp->drc_busy = (drctl_cookie_t)-1; 4741d4b38e0Srsmaeda mutex_exit(&drctlp->drc_lock); 4751d4b38e0Srsmaeda 47699c7e855SJames Marks - Sun Microsystems rv = drctl_config_common(cmd, flags, res, count, rbuf, rsize, &rq_size); 47799c7e855SJames Marks - Sun Microsystems if (rv == 0) { 47899c7e855SJames Marks - Sun Microsystems /* 47999c7e855SJames Marks - Sun Microsystems * If the upcall to the daemon returned successfully, we 48099c7e855SJames Marks - Sun Microsystems * still need to validate the format of the returned msg. 48199c7e855SJames Marks - Sun Microsystems */ 48299c7e855SJames Marks - Sun Microsystems if ((rv = verify_response(cmd, 48399c7e855SJames Marks - Sun Microsystems count, *rbuf, rq_size, *rsize)) != 0) { 48499c7e855SJames Marks - Sun Microsystems DR_DBG_KMEM("%s: free addr %p size %ld\n", 48599c7e855SJames Marks - Sun Microsystems __func__, (void *)*rbuf, *rsize); 48699c7e855SJames Marks - Sun Microsystems kmem_free(*rbuf, *rsize); 48799c7e855SJames Marks - Sun Microsystems *rbuf = drctl_generate_err_resp(rsp_msg, rsize); 48899c7e855SJames Marks - Sun Microsystems drctlp->drc_busy = NULL; 489af4c679fSSean McEnroe cv_broadcast(&drctlp->drc_busy_cv); 49099c7e855SJames Marks - Sun Microsystems } else { /* message format is valid */ 4911d4b38e0Srsmaeda drctlp->drc_busy = ck; 4921d4b38e0Srsmaeda drctlp->drc_cmd = cmd; 4931d4b38e0Srsmaeda drctlp->drc_flags = flags; 4941d4b38e0Srsmaeda } 4951d4b38e0Srsmaeda } else { 49699c7e855SJames Marks - Sun Microsystems switch (rv) { 49799c7e855SJames Marks - Sun Microsystems case ENOTSUP: 49899c7e855SJames Marks - Sun Microsystems ermsg = unsup_msg; 49999c7e855SJames Marks - Sun Microsystems break; 50099c7e855SJames Marks - Sun Microsystems case EIO: 50199c7e855SJames Marks - Sun Microsystems ermsg = drd_msg; 50299c7e855SJames Marks - Sun Microsystems break; 50399c7e855SJames Marks - Sun Microsystems default: 50499c7e855SJames Marks - Sun Microsystems ermsg = unk_msg; 50599c7e855SJames Marks - Sun Microsystems break; 50699c7e855SJames Marks - Sun Microsystems } 50799c7e855SJames Marks - Sun Microsystems 50899c7e855SJames Marks - Sun Microsystems *rbuf = drctl_generate_err_resp(ermsg, rsize); 50999c7e855SJames Marks - Sun Microsystems 5101d4b38e0Srsmaeda drctlp->drc_cmd = -1; 5111d4b38e0Srsmaeda drctlp->drc_flags = 0; 5121d4b38e0Srsmaeda drctlp->drc_busy = NULL; 513af4c679fSSean McEnroe cv_broadcast(&drctlp->drc_busy_cv); 5141d4b38e0Srsmaeda } 5151d4b38e0Srsmaeda return (rv); 5161d4b38e0Srsmaeda } 5171d4b38e0Srsmaeda 5181d4b38e0Srsmaeda /* 5191d4b38e0Srsmaeda * Complete a reconfig operation. 5201d4b38e0Srsmaeda */ 5211d4b38e0Srsmaeda int 5221d4b38e0Srsmaeda drctl_config_fini(drctl_cookie_t ck, drctl_rsrc_t *res, int count) 5231d4b38e0Srsmaeda { 5241d4b38e0Srsmaeda int rv; 5251d4b38e0Srsmaeda int notify_cmd; 5261d4b38e0Srsmaeda int flags; 52799c7e855SJames Marks - Sun Microsystems size_t rq_size; 5281d4b38e0Srsmaeda 5291d4b38e0Srsmaeda mutex_enter(&drctlp->drc_lock); 5301d4b38e0Srsmaeda if (drctlp->drc_busy != ck) { 5311d4b38e0Srsmaeda mutex_exit(&drctlp->drc_lock); 5321d4b38e0Srsmaeda return (EBUSY); 5331d4b38e0Srsmaeda } 5341d4b38e0Srsmaeda mutex_exit(&drctlp->drc_lock); 5351d4b38e0Srsmaeda 5361d4b38e0Srsmaeda flags = drctlp->drc_flags; 5371d4b38e0Srsmaeda /* 5381d4b38e0Srsmaeda * Flip the saved _REQUEST command to its corresponding 5391d4b38e0Srsmaeda * _NOTIFY command. 5401d4b38e0Srsmaeda */ 5411d4b38e0Srsmaeda switch (drctlp->drc_cmd) { 5421d4b38e0Srsmaeda case DRCTL_CPU_CONFIG_REQUEST: 5431d4b38e0Srsmaeda notify_cmd = DRCTL_CPU_CONFIG_NOTIFY; 5441d4b38e0Srsmaeda break; 5451d4b38e0Srsmaeda 5461d4b38e0Srsmaeda case DRCTL_CPU_UNCONFIG_REQUEST: 5471d4b38e0Srsmaeda notify_cmd = DRCTL_CPU_UNCONFIG_NOTIFY; 5481d4b38e0Srsmaeda break; 5491d4b38e0Srsmaeda 5508fea755aSjm22469 case DRCTL_IO_UNCONFIG_REQUEST: 5518fea755aSjm22469 notify_cmd = DRCTL_IO_UNCONFIG_NOTIFY; 5528fea755aSjm22469 break; 5538fea755aSjm22469 5548fea755aSjm22469 case DRCTL_IO_CONFIG_REQUEST: 5558fea755aSjm22469 notify_cmd = DRCTL_IO_CONFIG_NOTIFY; 5568fea755aSjm22469 break; 5578fea755aSjm22469 5581d4b38e0Srsmaeda case DRCTL_MEM_CONFIG_REQUEST: 5599853d9e8SJason Beloro notify_cmd = DRCTL_MEM_CONFIG_NOTIFY; 5609853d9e8SJason Beloro break; 5619853d9e8SJason Beloro 5621d4b38e0Srsmaeda case DRCTL_MEM_UNCONFIG_REQUEST: 5639853d9e8SJason Beloro notify_cmd = DRCTL_MEM_UNCONFIG_NOTIFY; 5649853d9e8SJason Beloro break; 5659853d9e8SJason Beloro 5661d4b38e0Srsmaeda default: 5671d4b38e0Srsmaeda /* none of the above should have been accepted in _init */ 5681d4b38e0Srsmaeda ASSERT(0); 5691d4b38e0Srsmaeda cmn_err(CE_CONT, 5701d4b38e0Srsmaeda "drctl_config_fini: bad cmd %d\n", drctlp->drc_cmd); 5711d4b38e0Srsmaeda rv = EINVAL; 5721d4b38e0Srsmaeda goto done; 5731d4b38e0Srsmaeda } 5741d4b38e0Srsmaeda 57599c7e855SJames Marks - Sun Microsystems rv = drctl_config_common(notify_cmd, 57699c7e855SJames Marks - Sun Microsystems flags, res, count, NULL, 0, &rq_size); 5771d4b38e0Srsmaeda 5781d4b38e0Srsmaeda done: 5791d4b38e0Srsmaeda drctlp->drc_cmd = -1; 5801d4b38e0Srsmaeda drctlp->drc_flags = 0; 5811d4b38e0Srsmaeda drctlp->drc_busy = NULL; 582af4c679fSSean McEnroe cv_broadcast(&drctlp->drc_busy_cv); 5831d4b38e0Srsmaeda return (rv); 5841d4b38e0Srsmaeda } 5851d4b38e0Srsmaeda 5861d4b38e0Srsmaeda static int 5871d4b38e0Srsmaeda drctl_ioctl(dev_t dev, 5881d4b38e0Srsmaeda int cmd, intptr_t arg, int mode, cred_t *cred_p, int *rval_p) 5891d4b38e0Srsmaeda { 5901d4b38e0Srsmaeda _NOTE(ARGUNUSED(dev, mode, cred_p, rval_p)) 5911d4b38e0Srsmaeda 5921d4b38e0Srsmaeda int rv; 5931d4b38e0Srsmaeda 5941d4b38e0Srsmaeda switch (cmd) { 5951d4b38e0Srsmaeda case DRCTL_IOCTL_CONNECT_SERVER: 5961d4b38e0Srsmaeda rv = i_drctl_ioctl(cmd, arg); 5971d4b38e0Srsmaeda break; 5981d4b38e0Srsmaeda default: 5991d4b38e0Srsmaeda rv = ENOTSUP; 6001d4b38e0Srsmaeda } 6011d4b38e0Srsmaeda 6021d4b38e0Srsmaeda *rval_p = (rv == 0) ? 0 : -1; 6031d4b38e0Srsmaeda 6041d4b38e0Srsmaeda return (rv); 6051d4b38e0Srsmaeda } 6061d4b38e0Srsmaeda 6071d4b38e0Srsmaeda /* 6081d4b38e0Srsmaeda * Accept a preformatted request from caller and send a message to 6091d4b38e0Srsmaeda * the daemon. A pointer to the daemon's response buffer is passed 6101d4b38e0Srsmaeda * back in obufp, its size in osize. 6111d4b38e0Srsmaeda */ 6121d4b38e0Srsmaeda static int 61399c7e855SJames Marks - Sun Microsystems send_message(void *msg, size_t size, drctl_resp_t **obufp, size_t *osize) 6141d4b38e0Srsmaeda { 61599c7e855SJames Marks - Sun Microsystems drctl_resp_t *bufp; 61699c7e855SJames Marks - Sun Microsystems drctl_rsrc_t *rsrcs; 61799c7e855SJames Marks - Sun Microsystems size_t rsrcs_size; 6181d4b38e0Srsmaeda int rv; 6191d4b38e0Srsmaeda 62099c7e855SJames Marks - Sun Microsystems rv = i_drctl_send(msg, size, (void **)&rsrcs, &rsrcs_size); 6211d4b38e0Srsmaeda 62299c7e855SJames Marks - Sun Microsystems if ((rv == 0) && ((rsrcs == NULL) ||(rsrcs_size == 0))) 62399c7e855SJames Marks - Sun Microsystems rv = EINVAL; 62499c7e855SJames Marks - Sun Microsystems 62599c7e855SJames Marks - Sun Microsystems if (rv == 0) { 62699c7e855SJames Marks - Sun Microsystems if (obufp != NULL) { 62799c7e855SJames Marks - Sun Microsystems ASSERT(osize != NULL); 62899c7e855SJames Marks - Sun Microsystems 62999c7e855SJames Marks - Sun Microsystems *osize = 63099c7e855SJames Marks - Sun Microsystems offsetof(drctl_resp_t, resp_resources) + rsrcs_size; 63199c7e855SJames Marks - Sun Microsystems bufp = 63299c7e855SJames Marks - Sun Microsystems kmem_alloc(*osize, KM_SLEEP); 63399c7e855SJames Marks - Sun Microsystems DR_DBG_KMEM("%s: alloc addr %p size %ld\n", 63499c7e855SJames Marks - Sun Microsystems __func__, (void *)bufp, *osize); 63599c7e855SJames Marks - Sun Microsystems bufp->resp_type = DRCTL_RESP_OK; 63699c7e855SJames Marks - Sun Microsystems bcopy(rsrcs, bufp->resp_resources, rsrcs_size); 63799c7e855SJames Marks - Sun Microsystems *obufp = bufp; 63899c7e855SJames Marks - Sun Microsystems } 63999c7e855SJames Marks - Sun Microsystems 64099c7e855SJames Marks - Sun Microsystems DR_DBG_KMEM("%s: free addr %p size %ld\n", 64199c7e855SJames Marks - Sun Microsystems __func__, (void *)rsrcs, rsrcs_size); 64299c7e855SJames Marks - Sun Microsystems kmem_free(rsrcs, rsrcs_size); 64399c7e855SJames Marks - Sun Microsystems } 64499c7e855SJames Marks - Sun Microsystems 64599c7e855SJames Marks - Sun Microsystems DR_DBG_KMEM("%s:free addr %p size %ld\n", __func__, msg, size); 6461d4b38e0Srsmaeda kmem_free(msg, size); 6471d4b38e0Srsmaeda 6481d4b38e0Srsmaeda return (rv); 6491d4b38e0Srsmaeda } 6501d4b38e0Srsmaeda 6511d4b38e0Srsmaeda static void * 65299c7e855SJames Marks - Sun Microsystems pack_message(int cmd, 65399c7e855SJames Marks - Sun Microsystems int flags, int count, void *data, size_t *osize, size_t *data_size) 6541d4b38e0Srsmaeda { 6558fea755aSjm22469 drd_msg_t *msgp = NULL; 6561d4b38e0Srsmaeda size_t hdr_size = offsetof(drd_msg_t, data); 6571d4b38e0Srsmaeda 6581d4b38e0Srsmaeda switch (cmd) { 6591d4b38e0Srsmaeda case DRCTL_CPU_CONFIG_REQUEST: 6601d4b38e0Srsmaeda case DRCTL_CPU_CONFIG_NOTIFY: 6611d4b38e0Srsmaeda case DRCTL_CPU_UNCONFIG_REQUEST: 6621d4b38e0Srsmaeda case DRCTL_CPU_UNCONFIG_NOTIFY: 66399c7e855SJames Marks - Sun Microsystems *data_size = count * sizeof (drctl_rsrc_t); 6648fea755aSjm22469 break; 6659853d9e8SJason Beloro case DRCTL_MEM_CONFIG_REQUEST: 6669853d9e8SJason Beloro case DRCTL_MEM_CONFIG_NOTIFY: 6679853d9e8SJason Beloro case DRCTL_MEM_UNCONFIG_REQUEST: 6689853d9e8SJason Beloro case DRCTL_MEM_UNCONFIG_NOTIFY: 6699853d9e8SJason Beloro *data_size = count * sizeof (drctl_rsrc_t); 6709853d9e8SJason Beloro break; 6718fea755aSjm22469 case DRCTL_IO_CONFIG_REQUEST: 6728fea755aSjm22469 case DRCTL_IO_CONFIG_NOTIFY: 6738fea755aSjm22469 case DRCTL_IO_UNCONFIG_REQUEST: 6748fea755aSjm22469 case DRCTL_IO_UNCONFIG_NOTIFY: 67599c7e855SJames Marks - Sun Microsystems *data_size = sizeof (drctl_rsrc_t) + 6768fea755aSjm22469 strlen(((drctl_rsrc_t *)data)->res_dev_path); 6771d4b38e0Srsmaeda break; 6781d4b38e0Srsmaeda default: 6791d4b38e0Srsmaeda cmn_err(CE_WARN, 6801d4b38e0Srsmaeda "drctl: pack_message received invalid cmd %d", cmd); 6818fea755aSjm22469 break; 6828fea755aSjm22469 } 6838fea755aSjm22469 6848fea755aSjm22469 if (data_size) { 68599c7e855SJames Marks - Sun Microsystems *osize = hdr_size + *data_size; 6868fea755aSjm22469 msgp = kmem_alloc(*osize, KM_SLEEP); 68799c7e855SJames Marks - Sun Microsystems DR_DBG_KMEM("%s: alloc addr %p size %ld\n", 68899c7e855SJames Marks - Sun Microsystems __func__, (void *)msgp, *osize); 6898fea755aSjm22469 msgp->cmd = cmd; 6908fea755aSjm22469 msgp->count = count; 6918fea755aSjm22469 msgp->flags = flags; 69299c7e855SJames Marks - Sun Microsystems bcopy(data, msgp->data, *data_size); 6931d4b38e0Srsmaeda } 6941d4b38e0Srsmaeda 6951d4b38e0Srsmaeda return (msgp); 6961d4b38e0Srsmaeda } 697af4c679fSSean McEnroe 698af4c679fSSean McEnroe /* 699*02b4e56cSHaik Aftandilian * Depending on the should_block argument, either wait for ongoing DR 700*02b4e56cSHaik Aftandilian * operations to finish and then block subsequent operations, or if a DR 701*02b4e56cSHaik Aftandilian * operation is already in progress, return EBUSY immediately without 702*02b4e56cSHaik Aftandilian * blocking subsequent DR operations. 703af4c679fSSean McEnroe */ 704*02b4e56cSHaik Aftandilian static int 705*02b4e56cSHaik Aftandilian drctl_block_conditional(boolean_t should_block) 706af4c679fSSean McEnroe { 707af4c679fSSean McEnroe mutex_enter(&drctlp->drc_lock); 708*02b4e56cSHaik Aftandilian /* If DR in progress and should_block is false, return */ 709*02b4e56cSHaik Aftandilian if (!should_block && drctlp->drc_busy != NULL) { 710*02b4e56cSHaik Aftandilian mutex_exit(&drctlp->drc_lock); 711*02b4e56cSHaik Aftandilian return (EBUSY); 712*02b4e56cSHaik Aftandilian } 713*02b4e56cSHaik Aftandilian 714*02b4e56cSHaik Aftandilian /* Wait for any in progress DR operation to complete */ 715af4c679fSSean McEnroe while (drctlp->drc_busy != NULL) 716af4c679fSSean McEnroe (void) cv_wait_sig(&drctlp->drc_busy_cv, &drctlp->drc_lock); 717*02b4e56cSHaik Aftandilian 718af4c679fSSean McEnroe /* Mark the link busy */ 719af4c679fSSean McEnroe drctlp->drc_busy = (drctl_cookie_t)-1; 720af4c679fSSean McEnroe drctlp->drc_cmd = DRCTL_DRC_BLOCK; 721af4c679fSSean McEnroe drctlp->drc_flags = 0; 722af4c679fSSean McEnroe mutex_exit(&drctlp->drc_lock); 723*02b4e56cSHaik Aftandilian return (0); 724*02b4e56cSHaik Aftandilian } 725*02b4e56cSHaik Aftandilian 726*02b4e56cSHaik Aftandilian /* 727*02b4e56cSHaik Aftandilian * Wait for ongoing DR operations to finish, block subsequent operations. 728*02b4e56cSHaik Aftandilian */ 729*02b4e56cSHaik Aftandilian void 730*02b4e56cSHaik Aftandilian drctl_block(void) 731*02b4e56cSHaik Aftandilian { 732*02b4e56cSHaik Aftandilian (void) drctl_block_conditional(B_TRUE); 733*02b4e56cSHaik Aftandilian } 734*02b4e56cSHaik Aftandilian 735*02b4e56cSHaik Aftandilian /* 736*02b4e56cSHaik Aftandilian * If a DR operation is already in progress, return EBUSY immediately 737*02b4e56cSHaik Aftandilian * without blocking subsequent DR operations. 738*02b4e56cSHaik Aftandilian */ 739*02b4e56cSHaik Aftandilian int 740*02b4e56cSHaik Aftandilian drctl_tryblock(void) 741*02b4e56cSHaik Aftandilian { 742*02b4e56cSHaik Aftandilian return (drctl_block_conditional(B_FALSE)); 743af4c679fSSean McEnroe } 744af4c679fSSean McEnroe 745af4c679fSSean McEnroe /* 746af4c679fSSean McEnroe * Unblock DR operations 747af4c679fSSean McEnroe */ 748af4c679fSSean McEnroe void 749af4c679fSSean McEnroe drctl_unblock(void) 750af4c679fSSean McEnroe { 751af4c679fSSean McEnroe /* Mark the link free */ 752af4c679fSSean McEnroe mutex_enter(&drctlp->drc_lock); 753af4c679fSSean McEnroe drctlp->drc_cmd = -1; 754af4c679fSSean McEnroe drctlp->drc_flags = 0; 755af4c679fSSean McEnroe drctlp->drc_busy = NULL; 756af4c679fSSean McEnroe cv_broadcast(&drctlp->drc_busy_cv); 757af4c679fSSean McEnroe mutex_exit(&drctlp->drc_lock); 758af4c679fSSean McEnroe } 759