xref: /titanic_44/usr/src/uts/sun4v/io/drctl.c (revision 02b4e56ca3a4e4a4fe9e52fca9c2972101f0e57f)
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
_init(void)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
_fini(void)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
_info(struct modinfo * modinfop)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
drctl_do_attach(dev_info_t * dip,ddi_attach_cmd_t cmd)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
drctl_attach(dev_info_t * dip,ddi_attach_cmd_t cmd)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
drctl_detach(dev_info_t * dip,ddi_detach_cmd_t cmd)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
drctl_getinfo(dev_info_t * dip,ddi_info_cmd_t cmd,void * arg,void ** resultp)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
drctl_open(dev_t * devp,int flag,int otyp,cred_t * cred_p)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
drctl_close(dev_t dev,int flag,int otyp,cred_t * cred_p)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 *
drctl_generate_resp(drctl_rsrc_t * res,int count,size_t * rsize,drctl_status_t status)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 *
drctl_generate_err_resp(char * msg,size_t * size)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
verify_response(int cmd,int count,drctl_resp_t * resp,size_t sent_len,size_t resp_len)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
drctl_config_common(int cmd,int flags,drctl_rsrc_t * res,int count,drctl_resp_t ** rbuf,size_t * rsize,size_t * rq_size)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
drctl_config_init(int cmd,int flags,drctl_rsrc_t * res,int count,drctl_resp_t ** rbuf,size_t * rsize,drctl_cookie_t ck)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
drctl_config_fini(drctl_cookie_t ck,drctl_rsrc_t * res,int count)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
drctl_ioctl(dev_t dev,int cmd,intptr_t arg,int mode,cred_t * cred_p,int * rval_p)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
send_message(void * msg,size_t size,drctl_resp_t ** obufp,size_t * osize)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 *
pack_message(int cmd,int flags,int count,void * data,size_t * osize,size_t * data_size)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
drctl_block_conditional(boolean_t should_block)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
drctl_block(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
drctl_tryblock(void)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
drctl_unblock(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