xref: /onnv-gate/usr/src/uts/sun4v/io/drctl.c (revision 2309:a4369449abc5)
1*2309Srsmaeda /*
2*2309Srsmaeda  * CDDL HEADER START
3*2309Srsmaeda  *
4*2309Srsmaeda  * The contents of this file are subject to the terms of the
5*2309Srsmaeda  * Common Development and Distribution License (the "License").
6*2309Srsmaeda  * You may not use this file except in compliance with the License.
7*2309Srsmaeda  *
8*2309Srsmaeda  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9*2309Srsmaeda  * or http://www.opensolaris.org/os/licensing.
10*2309Srsmaeda  * See the License for the specific language governing permissions
11*2309Srsmaeda  * and limitations under the License.
12*2309Srsmaeda  *
13*2309Srsmaeda  * When distributing Covered Code, include this CDDL HEADER in each
14*2309Srsmaeda  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15*2309Srsmaeda  * If applicable, add the following below this CDDL HEADER, with the
16*2309Srsmaeda  * fields enclosed by brackets "[]" replaced with your own identifying
17*2309Srsmaeda  * information: Portions Copyright [yyyy] [name of copyright owner]
18*2309Srsmaeda  *
19*2309Srsmaeda  * CDDL HEADER END
20*2309Srsmaeda  */
21*2309Srsmaeda 
22*2309Srsmaeda /*
23*2309Srsmaeda  * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
24*2309Srsmaeda  * Use is subject to license terms.
25*2309Srsmaeda  */
26*2309Srsmaeda 
27*2309Srsmaeda #pragma ident	"%Z%%M%	%I%	%E% SMI"
28*2309Srsmaeda 
29*2309Srsmaeda /*
30*2309Srsmaeda  * DR control module for LDoms
31*2309Srsmaeda  */
32*2309Srsmaeda 
33*2309Srsmaeda #include <sys/sysmacros.h>
34*2309Srsmaeda #include <sys/modctl.h>
35*2309Srsmaeda #include <sys/conf.h>
36*2309Srsmaeda #include <sys/ddi.h>
37*2309Srsmaeda #include <sys/sunddi.h>
38*2309Srsmaeda #include <sys/ddi_impldefs.h>
39*2309Srsmaeda #include <sys/stat.h>
40*2309Srsmaeda #include <sys/door.h>
41*2309Srsmaeda #include <sys/open.h>
42*2309Srsmaeda #include <sys/note.h>
43*2309Srsmaeda #include <sys/ldoms.h>
44*2309Srsmaeda #include <sys/dr_util.h>
45*2309Srsmaeda #include <sys/drctl.h>
46*2309Srsmaeda #include <sys/drctl_impl.h>
47*2309Srsmaeda 
48*2309Srsmaeda 
49*2309Srsmaeda static int drctl_attach(dev_info_t *, ddi_attach_cmd_t);
50*2309Srsmaeda static int drctl_detach(dev_info_t *, ddi_detach_cmd_t);
51*2309Srsmaeda static int drctl_getinfo(dev_info_t *, ddi_info_cmd_t, void *, void **);
52*2309Srsmaeda 
53*2309Srsmaeda static int drctl_open(dev_t *, int, int, cred_t *);
54*2309Srsmaeda static int drctl_close(dev_t, int, int, cred_t *);
55*2309Srsmaeda static int drctl_ioctl(dev_t, int, intptr_t, int, cred_t *, int *);
56*2309Srsmaeda 
57*2309Srsmaeda static void *pack_message(int, int, int, void *, size_t *);
58*2309Srsmaeda static int send_message(void *, size_t, void **, size_t *);
59*2309Srsmaeda 
60*2309Srsmaeda 
61*2309Srsmaeda /*
62*2309Srsmaeda  * Configuration data structures
63*2309Srsmaeda  */
64*2309Srsmaeda static struct cb_ops drctl_cb_ops = {
65*2309Srsmaeda 	drctl_open,		/* open */
66*2309Srsmaeda 	drctl_close,		/* close */
67*2309Srsmaeda 	nodev,			/* strategy */
68*2309Srsmaeda 	nodev,			/* print */
69*2309Srsmaeda 	nodev,			/* dump */
70*2309Srsmaeda 	nodev,			/* read */
71*2309Srsmaeda 	nodev,			/* write */
72*2309Srsmaeda 	drctl_ioctl,		/* ioctl */
73*2309Srsmaeda 	nodev,			/* devmap */
74*2309Srsmaeda 	nodev,			/* mmap */
75*2309Srsmaeda 	nodev,			/* segmap */
76*2309Srsmaeda 	nochpoll,		/* poll */
77*2309Srsmaeda 	ddi_prop_op,		/* prop_op */
78*2309Srsmaeda 	NULL,			/* streamtab */
79*2309Srsmaeda 	D_MP | D_NEW,		/* driver compatibility flag */
80*2309Srsmaeda 	CB_REV,			/* cb_ops revision */
81*2309Srsmaeda 	nodev,			/* async read */
82*2309Srsmaeda 	nodev			/* async write */
83*2309Srsmaeda };
84*2309Srsmaeda 
85*2309Srsmaeda 
86*2309Srsmaeda static struct dev_ops drctl_ops = {
87*2309Srsmaeda 	DEVO_REV,		/* devo_rev */
88*2309Srsmaeda 	0,			/* refcnt */
89*2309Srsmaeda 	drctl_getinfo,		/* info */
90*2309Srsmaeda 	nulldev,		/* identify */
91*2309Srsmaeda 	nulldev,		/* probe */
92*2309Srsmaeda 	drctl_attach,		/* attach */
93*2309Srsmaeda 	drctl_detach,		/* detach */
94*2309Srsmaeda 	nodev,			/* reset */
95*2309Srsmaeda 	&drctl_cb_ops,		/* driver operations */
96*2309Srsmaeda 	NULL,			/* bus operations */
97*2309Srsmaeda 	NULL,			/* power */
98*2309Srsmaeda };
99*2309Srsmaeda 
100*2309Srsmaeda static struct modldrv modldrv = {
101*2309Srsmaeda 	&mod_driverops,		/* type of module - driver */
102*2309Srsmaeda 	"DR Control pseudo driver v%I%",
103*2309Srsmaeda 	&drctl_ops
104*2309Srsmaeda };
105*2309Srsmaeda 
106*2309Srsmaeda static struct modlinkage modlinkage = {
107*2309Srsmaeda 	MODREV_1,
108*2309Srsmaeda 	&modldrv,
109*2309Srsmaeda 	NULL
110*2309Srsmaeda };
111*2309Srsmaeda 
112*2309Srsmaeda 
113*2309Srsmaeda /*
114*2309Srsmaeda  * Locking strategy
115*2309Srsmaeda  *
116*2309Srsmaeda  * One of the reasons for this module's existence is to serialize
117*2309Srsmaeda  * DR requests which might be coming from different sources.  Only
118*2309Srsmaeda  * one operation is allowed to be in progress at any given time.
119*2309Srsmaeda  *
120*2309Srsmaeda  * A single lock word (the 'drc_busy' element below) is NULL
121*2309Srsmaeda  * when there is no operation in progress.  When a client of this
122*2309Srsmaeda  * module initiates an operation it grabs the mutex 'drc_lock' in
123*2309Srsmaeda  * order to examine the lock word ('drc_busy').  If no other
124*2309Srsmaeda  * operation is in progress, the lock word will be NULL.  If so,
125*2309Srsmaeda  * a cookie which uniquely identifies the requestor is stored in
126*2309Srsmaeda  * the lock word, and the mutex is released.  Attempts by other
127*2309Srsmaeda  * clients to initiate an operation will fail.
128*2309Srsmaeda  *
129*2309Srsmaeda  * When the lock-holding client's operation is completed, the
130*2309Srsmaeda  * client will call a "finalize" function in this module, providing
131*2309Srsmaeda  * the cookie passed with the original request.  Since the cookie
132*2309Srsmaeda  * matches, the operation will succeed and the lock word will be
133*2309Srsmaeda  * cleared.  At this point, an new operation may be initiated.
134*2309Srsmaeda  */
135*2309Srsmaeda 
136*2309Srsmaeda /*
137*2309Srsmaeda  * Driver private data
138*2309Srsmaeda  */
139*2309Srsmaeda static struct drctl_unit {
140*2309Srsmaeda 	kmutex_t		drc_lock;	/* global driver lock */
141*2309Srsmaeda 	dev_info_t		*drc_dip;	/* dev_info pointer */
142*2309Srsmaeda 	kcondvar_t		drc_busy_cv;	/* block for !busy */
143*2309Srsmaeda 	drctl_cookie_t		drc_busy;	/* NULL if free else a unique */
144*2309Srsmaeda 						/* identifier for caller */
145*2309Srsmaeda 	int			drc_cmd;	/* the cmd underway (or -1) */
146*2309Srsmaeda 	int			drc_flags;	/* saved flag from above cmd */
147*2309Srsmaeda 	int			drc_inst;	/* our single instance */
148*2309Srsmaeda 	uint_t			drc_state;	/* driver state */
149*2309Srsmaeda } drctl_state;
150*2309Srsmaeda 
151*2309Srsmaeda static struct drctl_unit *drctlp = &drctl_state;
152*2309Srsmaeda 
153*2309Srsmaeda int
154*2309Srsmaeda _init(void)
155*2309Srsmaeda {
156*2309Srsmaeda 	drctlp->drc_inst = -1;
157*2309Srsmaeda 	mutex_init(&drctlp->drc_lock, NULL, MUTEX_DRIVER, NULL);
158*2309Srsmaeda 	return (mod_install(&modlinkage));
159*2309Srsmaeda }
160*2309Srsmaeda 
161*2309Srsmaeda 
162*2309Srsmaeda int
163*2309Srsmaeda _fini(void)
164*2309Srsmaeda {
165*2309Srsmaeda 	mutex_destroy(&drctlp->drc_lock);
166*2309Srsmaeda 	return (mod_remove(&modlinkage));
167*2309Srsmaeda }
168*2309Srsmaeda 
169*2309Srsmaeda 
170*2309Srsmaeda int
171*2309Srsmaeda _info(struct modinfo *modinfop)
172*2309Srsmaeda {
173*2309Srsmaeda 	return (mod_info(&modlinkage, modinfop));
174*2309Srsmaeda }
175*2309Srsmaeda 
176*2309Srsmaeda 
177*2309Srsmaeda /*
178*2309Srsmaeda  * Do the attach work
179*2309Srsmaeda  */
180*2309Srsmaeda static int
181*2309Srsmaeda drctl_do_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
182*2309Srsmaeda {
183*2309Srsmaeda 	_NOTE(ARGUNUSED(cmd))
184*2309Srsmaeda 
185*2309Srsmaeda 	char *str = "drctl_do_attach";
186*2309Srsmaeda 	int retval = DDI_SUCCESS;
187*2309Srsmaeda 
188*2309Srsmaeda 	if (drctlp->drc_inst != -1) {
189*2309Srsmaeda 		cmn_err(CE_WARN, "%s: an instance is already attached!", str);
190*2309Srsmaeda 		return (DDI_FAILURE);
191*2309Srsmaeda 	}
192*2309Srsmaeda 	drctlp->drc_inst = ddi_get_instance(dip);
193*2309Srsmaeda 
194*2309Srsmaeda 	retval = ddi_create_minor_node(dip, "drctl", S_IFCHR,
195*2309Srsmaeda 	    drctlp->drc_inst, DDI_PSEUDO, 0);
196*2309Srsmaeda 	if (retval != DDI_SUCCESS) {
197*2309Srsmaeda 		cmn_err(CE_WARN, "%s: can't create minor node", str);
198*2309Srsmaeda 		drctlp->drc_inst = -1;
199*2309Srsmaeda 		return (retval);
200*2309Srsmaeda 	}
201*2309Srsmaeda 
202*2309Srsmaeda 	drctlp->drc_dip = dip;
203*2309Srsmaeda 	ddi_report_dev(dip);
204*2309Srsmaeda 
205*2309Srsmaeda 	return (retval);
206*2309Srsmaeda }
207*2309Srsmaeda 
208*2309Srsmaeda 
209*2309Srsmaeda static int
210*2309Srsmaeda drctl_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
211*2309Srsmaeda {
212*2309Srsmaeda 	switch (cmd) {
213*2309Srsmaeda 	case DDI_ATTACH:
214*2309Srsmaeda 		return (drctl_do_attach(dip, cmd));
215*2309Srsmaeda 
216*2309Srsmaeda 	default:
217*2309Srsmaeda 		return (DDI_FAILURE);
218*2309Srsmaeda 	}
219*2309Srsmaeda }
220*2309Srsmaeda 
221*2309Srsmaeda 
222*2309Srsmaeda /* ARGSUSED */
223*2309Srsmaeda static int
224*2309Srsmaeda drctl_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
225*2309Srsmaeda {
226*2309Srsmaeda 	switch (cmd) {
227*2309Srsmaeda 	case DDI_DETACH:
228*2309Srsmaeda 		drctlp->drc_inst = -1;
229*2309Srsmaeda 		ddi_remove_minor_node(dip, "drctl");
230*2309Srsmaeda 		return (DDI_SUCCESS);
231*2309Srsmaeda 
232*2309Srsmaeda 	default:
233*2309Srsmaeda 		return (DDI_FAILURE);
234*2309Srsmaeda 	}
235*2309Srsmaeda }
236*2309Srsmaeda 
237*2309Srsmaeda static int
238*2309Srsmaeda drctl_getinfo(dev_info_t *dip, ddi_info_cmd_t cmd, void *arg, void **resultp)
239*2309Srsmaeda {
240*2309Srsmaeda 	_NOTE(ARGUNUSED(dip, cmd, arg, resultp))
241*2309Srsmaeda 
242*2309Srsmaeda 	return (0);
243*2309Srsmaeda }
244*2309Srsmaeda 
245*2309Srsmaeda static int
246*2309Srsmaeda drctl_open(dev_t *devp, int flag, int otyp, cred_t *cred_p)
247*2309Srsmaeda {
248*2309Srsmaeda 	_NOTE(ARGUNUSED(devp, flag, cred_p))
249*2309Srsmaeda 
250*2309Srsmaeda 	if (otyp != OTYP_CHR)
251*2309Srsmaeda 		return (EINVAL);
252*2309Srsmaeda 
253*2309Srsmaeda 	return (0);
254*2309Srsmaeda }
255*2309Srsmaeda 
256*2309Srsmaeda static int
257*2309Srsmaeda drctl_close(dev_t dev, int flag, int otyp, cred_t *cred_p)
258*2309Srsmaeda {
259*2309Srsmaeda 	_NOTE(ARGUNUSED(dev, flag, otyp, cred_p))
260*2309Srsmaeda 
261*2309Srsmaeda 	return (0);
262*2309Srsmaeda }
263*2309Srsmaeda 
264*2309Srsmaeda /*
265*2309Srsmaeda  * This driver guarantees that if drctl_config_init returns 0,
266*2309Srsmaeda  * a valid response buffer will be passed back to the caller.  This
267*2309Srsmaeda  * routine can be used to generate that response in cases where the
268*2309Srsmaeda  * upcall has not resulted in a response message from userland.
269*2309Srsmaeda  */
270*2309Srsmaeda static drctl_rsrc_t *
271*2309Srsmaeda drctl_generate_resp(drctl_rsrc_t *res,
272*2309Srsmaeda     int count, size_t *rsize, drctl_status_t status)
273*2309Srsmaeda {
274*2309Srsmaeda 	int		idx;
275*2309Srsmaeda 	size_t		size;
276*2309Srsmaeda 	drctl_rsrc_t	*rbuf;
277*2309Srsmaeda 
278*2309Srsmaeda 	size = count * sizeof (*res);
279*2309Srsmaeda 	rbuf  = kmem_alloc(size, KM_SLEEP);
280*2309Srsmaeda 
281*2309Srsmaeda 	bcopy(res, rbuf, size);
282*2309Srsmaeda 
283*2309Srsmaeda 	for (idx = 0; idx < count; idx++) {
284*2309Srsmaeda 		rbuf[idx].status = status;
285*2309Srsmaeda 		rbuf[idx].offset = 0;
286*2309Srsmaeda 	}
287*2309Srsmaeda 
288*2309Srsmaeda 	*rsize = size;
289*2309Srsmaeda 	return (rbuf);
290*2309Srsmaeda }
291*2309Srsmaeda 
292*2309Srsmaeda static int
293*2309Srsmaeda drctl_config_common(int cmd, int flags, drctl_rsrc_t *res,
294*2309Srsmaeda     int count, drctl_rsrc_t **rbuf, size_t *rsize)
295*2309Srsmaeda {
296*2309Srsmaeda 	int	rv = 0;
297*2309Srsmaeda 	size_t	size;
298*2309Srsmaeda 	char	*bufp;
299*2309Srsmaeda 	static const char me[] = "drctl_config_common";
300*2309Srsmaeda 
301*2309Srsmaeda 	switch (cmd) {
302*2309Srsmaeda 	case DRCTL_CPU_CONFIG_REQUEST:
303*2309Srsmaeda 	case DRCTL_CPU_CONFIG_NOTIFY:
304*2309Srsmaeda 	case DRCTL_CPU_UNCONFIG_REQUEST:
305*2309Srsmaeda 	case DRCTL_CPU_UNCONFIG_NOTIFY:
306*2309Srsmaeda 		rv = 0;
307*2309Srsmaeda 		break;
308*2309Srsmaeda 	case DRCTL_MEM_CONFIG_REQUEST:
309*2309Srsmaeda 	case DRCTL_MEM_CONFIG_NOTIFY:
310*2309Srsmaeda 	case DRCTL_MEM_UNCONFIG_REQUEST:
311*2309Srsmaeda 	case DRCTL_MEM_UNCONFIG_NOTIFY:
312*2309Srsmaeda 	case DRCTL_IO_CONFIG_REQUEST:
313*2309Srsmaeda 	case DRCTL_IO_CONFIG_NOTIFY:
314*2309Srsmaeda 	case DRCTL_IO_UNCONFIG_REQUEST:
315*2309Srsmaeda 	case DRCTL_IO_UNCONFIG_NOTIFY:
316*2309Srsmaeda 		rv = ENOTSUP;
317*2309Srsmaeda 		break;
318*2309Srsmaeda 	}
319*2309Srsmaeda 
320*2309Srsmaeda 	if (rv != 0) {
321*2309Srsmaeda 		DR_DBG_CTL("%s: invalid cmd %d\n", me, cmd);
322*2309Srsmaeda 		return (rv);
323*2309Srsmaeda 	}
324*2309Srsmaeda 
325*2309Srsmaeda 	/*
326*2309Srsmaeda 	 * If the operation is a FORCE, we don't send a message to
327*2309Srsmaeda 	 * the daemon.  But, the upstream clients still expect a
328*2309Srsmaeda 	 * response, so generate a response with all ops 'allowed'.
329*2309Srsmaeda 	 */
330*2309Srsmaeda 	if (flags == DRCTL_FLAG_FORCE) {
331*2309Srsmaeda 		if (rbuf != NULL) {
332*2309Srsmaeda 			*rbuf = drctl_generate_resp(res, count, &size,
333*2309Srsmaeda 			    DRCTL_STATUS_ALLOW);
334*2309Srsmaeda 			*rsize = size;
335*2309Srsmaeda 		}
336*2309Srsmaeda 		return (0);
337*2309Srsmaeda 	}
338*2309Srsmaeda 
339*2309Srsmaeda 	bufp = pack_message(cmd, flags, count, (void *)res, &size);
340*2309Srsmaeda 	DR_DBG_CTL("%s: from pack_message, bufp = %p size %ld\n",
341*2309Srsmaeda 	    me, (void *)bufp, size);
342*2309Srsmaeda 	if (bufp == NULL || size == 0)
343*2309Srsmaeda 		return (EIO);
344*2309Srsmaeda 
345*2309Srsmaeda 	rv = send_message(bufp, size, (void **)rbuf, rsize);
346*2309Srsmaeda 
347*2309Srsmaeda 	/*
348*2309Srsmaeda 	 * For failure, as part of our contract with the caller,
349*2309Srsmaeda 	 * generate a response message, but mark all proposed
350*2309Srsmaeda 	 * changes as 'denied'.
351*2309Srsmaeda 	 */
352*2309Srsmaeda 	if (rv != 0) {
353*2309Srsmaeda 		*rbuf = drctl_generate_resp(res, count, &size,
354*2309Srsmaeda 		    DRCTL_STATUS_DENY);
355*2309Srsmaeda 		*rsize = size;
356*2309Srsmaeda 	}
357*2309Srsmaeda 
358*2309Srsmaeda 	return (rv);
359*2309Srsmaeda }
360*2309Srsmaeda 
361*2309Srsmaeda /*
362*2309Srsmaeda  * Since the response comes from userland, make sure it is
363*2309Srsmaeda  * at least the minimum size and, if it contains error
364*2309Srsmaeda  * strings, that the string area is null-terminated.
365*2309Srsmaeda  */
366*2309Srsmaeda static int
367*2309Srsmaeda verify_response(int count, drctl_rsrc_t *resp, size_t size)
368*2309Srsmaeda {
369*2309Srsmaeda 	int idx;
370*2309Srsmaeda 	int need_terminator = 0;
371*2309Srsmaeda 	static const char me[] = "verify_response";
372*2309Srsmaeda 
373*2309Srsmaeda 	if (resp == NULL || size < count * sizeof (*resp)) {
374*2309Srsmaeda 		DR_DBG_CTL("%s: BAD size - count %d size %ld\n",
375*2309Srsmaeda 		    me, count, size);
376*2309Srsmaeda 		return (EIO);
377*2309Srsmaeda 	}
378*2309Srsmaeda 
379*2309Srsmaeda 	for (idx = 0; idx < count; idx++) {
380*2309Srsmaeda 
381*2309Srsmaeda 		if (resp[idx].offset != 0)
382*2309Srsmaeda 			need_terminator++;
383*2309Srsmaeda 	}
384*2309Srsmaeda 
385*2309Srsmaeda 	if (need_terminator && *((caddr_t)(resp) + size - 1) != '\0') {
386*2309Srsmaeda 		DR_DBG_CTL("%s: unterm. strings: resp %p size %ld char %d\n",
387*2309Srsmaeda 		    me, (void *)resp, size, *((caddr_t)(resp) + size - 1));
388*2309Srsmaeda 		/* Don't fail the transaction, but don't advertise strings */
389*2309Srsmaeda 		for (idx = 0; idx < count; idx++)
390*2309Srsmaeda 			resp[idx].offset = 0;
391*2309Srsmaeda 	}
392*2309Srsmaeda 
393*2309Srsmaeda 	return (0);
394*2309Srsmaeda }
395*2309Srsmaeda 
396*2309Srsmaeda 
397*2309Srsmaeda /*
398*2309Srsmaeda  * Prepare for a reconfig operation.
399*2309Srsmaeda  */
400*2309Srsmaeda int
401*2309Srsmaeda drctl_config_init(int cmd, int flags, drctl_rsrc_t *res,
402*2309Srsmaeda     int count, drctl_rsrc_t **rbuf, size_t *rsize, drctl_cookie_t ck)
403*2309Srsmaeda {
404*2309Srsmaeda 	static char me[] = "drctl_config_init";
405*2309Srsmaeda 	int idx;
406*2309Srsmaeda 	int rv;
407*2309Srsmaeda 
408*2309Srsmaeda 	if (ck == 0)
409*2309Srsmaeda 		return (EINVAL);
410*2309Srsmaeda 
411*2309Srsmaeda 	mutex_enter(&drctlp->drc_lock);
412*2309Srsmaeda 
413*2309Srsmaeda 	if (drctlp->drc_busy != NULL) {
414*2309Srsmaeda 		mutex_exit(&drctlp->drc_lock);
415*2309Srsmaeda 		return (EBUSY);
416*2309Srsmaeda 	}
417*2309Srsmaeda 
418*2309Srsmaeda 	DR_DBG_CTL("%s: cmd %d flags %d res %p count %d\n",
419*2309Srsmaeda 	    me, cmd, flags, (void *)res, count);
420*2309Srsmaeda 
421*2309Srsmaeda 	/* Mark the link busy.  Below we will fill in the actual cookie. */
422*2309Srsmaeda 	drctlp->drc_busy = (drctl_cookie_t)-1;
423*2309Srsmaeda 	mutex_exit(&drctlp->drc_lock);
424*2309Srsmaeda 
425*2309Srsmaeda 	if ((rv = drctl_config_common(cmd,
426*2309Srsmaeda 	    flags, res, count, rbuf, rsize)) == 0 &&
427*2309Srsmaeda 	    verify_response(count, *rbuf, *rsize) == 0) {
428*2309Srsmaeda 		drctlp->drc_busy = ck;
429*2309Srsmaeda 		drctlp->drc_cmd = cmd;
430*2309Srsmaeda 		drctlp->drc_flags = flags;
431*2309Srsmaeda 
432*2309Srsmaeda 		/*
433*2309Srsmaeda 		 * If there wasn't a valid response msg passed back,
434*2309Srsmaeda 		 * create a response with each resource op denied.
435*2309Srsmaeda 		 */
436*2309Srsmaeda 		if (*rbuf == NULL || *rsize == 0) {
437*2309Srsmaeda 			drctl_rsrc_t *bp = *rbuf;
438*2309Srsmaeda 
439*2309Srsmaeda 			*rsize = count * sizeof (*bp);
440*2309Srsmaeda 			bp = kmem_zalloc(*rsize, KM_SLEEP);
441*2309Srsmaeda 			bcopy(res, bp, *rsize);
442*2309Srsmaeda 
443*2309Srsmaeda 			for (idx = 0; idx < count; idx++) {
444*2309Srsmaeda 				bp[idx].status = DRCTL_STATUS_DENY;
445*2309Srsmaeda 				bp[idx].offset = 0;
446*2309Srsmaeda 			}
447*2309Srsmaeda 		}
448*2309Srsmaeda 	} else {
449*2309Srsmaeda 		drctlp->drc_cmd = -1;
450*2309Srsmaeda 		drctlp->drc_flags = 0;
451*2309Srsmaeda 		drctlp->drc_busy = NULL;
452*2309Srsmaeda 	}
453*2309Srsmaeda 
454*2309Srsmaeda 	return (rv);
455*2309Srsmaeda }
456*2309Srsmaeda 
457*2309Srsmaeda /*
458*2309Srsmaeda  * Complete a reconfig operation.
459*2309Srsmaeda  */
460*2309Srsmaeda int
461*2309Srsmaeda drctl_config_fini(drctl_cookie_t ck, drctl_rsrc_t *res, int count)
462*2309Srsmaeda {
463*2309Srsmaeda 	int rv;
464*2309Srsmaeda 	int notify_cmd;
465*2309Srsmaeda 	int flags;
466*2309Srsmaeda 
467*2309Srsmaeda 	mutex_enter(&drctlp->drc_lock);
468*2309Srsmaeda 
469*2309Srsmaeda 	if (drctlp->drc_busy != ck) {
470*2309Srsmaeda 		mutex_exit(&drctlp->drc_lock);
471*2309Srsmaeda 		return (EBUSY);
472*2309Srsmaeda 	}
473*2309Srsmaeda 
474*2309Srsmaeda 	mutex_exit(&drctlp->drc_lock);
475*2309Srsmaeda 
476*2309Srsmaeda 	flags = drctlp->drc_flags;
477*2309Srsmaeda 	/*
478*2309Srsmaeda 	 * Flip the saved _REQUEST command to its corresponding
479*2309Srsmaeda 	 * _NOTIFY command.
480*2309Srsmaeda 	 */
481*2309Srsmaeda 	switch (drctlp->drc_cmd) {
482*2309Srsmaeda 	case DRCTL_CPU_CONFIG_REQUEST:
483*2309Srsmaeda 		notify_cmd = DRCTL_CPU_CONFIG_NOTIFY;
484*2309Srsmaeda 		break;
485*2309Srsmaeda 
486*2309Srsmaeda 	case DRCTL_CPU_UNCONFIG_REQUEST:
487*2309Srsmaeda 		notify_cmd = DRCTL_CPU_UNCONFIG_NOTIFY;
488*2309Srsmaeda 		break;
489*2309Srsmaeda 
490*2309Srsmaeda 	case DRCTL_MEM_CONFIG_REQUEST:
491*2309Srsmaeda 	case DRCTL_MEM_CONFIG_NOTIFY:
492*2309Srsmaeda 	case DRCTL_MEM_UNCONFIG_REQUEST:
493*2309Srsmaeda 	case DRCTL_MEM_UNCONFIG_NOTIFY:
494*2309Srsmaeda 	case DRCTL_IO_CONFIG_REQUEST:
495*2309Srsmaeda 	case DRCTL_IO_CONFIG_NOTIFY:
496*2309Srsmaeda 	case DRCTL_IO_UNCONFIG_REQUEST:
497*2309Srsmaeda 	case DRCTL_IO_UNCONFIG_NOTIFY:
498*2309Srsmaeda 	default:
499*2309Srsmaeda 		/* none of the above should have been accepted in _init */
500*2309Srsmaeda 		ASSERT(0);
501*2309Srsmaeda 		cmn_err(CE_CONT,
502*2309Srsmaeda 		    "drctl_config_fini: bad cmd %d\n", drctlp->drc_cmd);
503*2309Srsmaeda 		rv = EINVAL;
504*2309Srsmaeda 		goto done;
505*2309Srsmaeda 	}
506*2309Srsmaeda 
507*2309Srsmaeda 	rv = drctl_config_common(notify_cmd, flags, res, count, NULL, 0);
508*2309Srsmaeda 
509*2309Srsmaeda done:
510*2309Srsmaeda 	drctlp->drc_cmd = -1;
511*2309Srsmaeda 	drctlp->drc_flags = 0;
512*2309Srsmaeda 	drctlp->drc_busy = NULL;
513*2309Srsmaeda 
514*2309Srsmaeda 	return (rv);
515*2309Srsmaeda }
516*2309Srsmaeda 
517*2309Srsmaeda static int
518*2309Srsmaeda drctl_ioctl(dev_t dev,
519*2309Srsmaeda     int cmd, intptr_t arg, int mode, cred_t *cred_p, int *rval_p)
520*2309Srsmaeda {
521*2309Srsmaeda 	_NOTE(ARGUNUSED(dev, mode, cred_p, rval_p))
522*2309Srsmaeda 
523*2309Srsmaeda 	int rv;
524*2309Srsmaeda 
525*2309Srsmaeda 	switch (cmd) {
526*2309Srsmaeda 	case DRCTL_IOCTL_CONNECT_SERVER:
527*2309Srsmaeda 		rv = i_drctl_ioctl(cmd, arg);
528*2309Srsmaeda 		break;
529*2309Srsmaeda 	default:
530*2309Srsmaeda 		rv = ENOTSUP;
531*2309Srsmaeda 	}
532*2309Srsmaeda 
533*2309Srsmaeda 	*rval_p = (rv == 0) ? 0 : -1;
534*2309Srsmaeda 
535*2309Srsmaeda 	return (rv);
536*2309Srsmaeda }
537*2309Srsmaeda 
538*2309Srsmaeda /*
539*2309Srsmaeda  * Accept a preformatted request from caller and send a message to
540*2309Srsmaeda  * the daemon.  A pointer to the daemon's response buffer is passed
541*2309Srsmaeda  * back in obufp, its size in osize.
542*2309Srsmaeda  */
543*2309Srsmaeda static int
544*2309Srsmaeda send_message(void *msg, size_t size, void **obufp, size_t *osize)
545*2309Srsmaeda {
546*2309Srsmaeda 	int rv;
547*2309Srsmaeda 
548*2309Srsmaeda 	rv = i_drctl_send(msg, size, obufp, osize);
549*2309Srsmaeda 
550*2309Srsmaeda 	kmem_free(msg, size);
551*2309Srsmaeda 
552*2309Srsmaeda 	return (rv);
553*2309Srsmaeda }
554*2309Srsmaeda 
555*2309Srsmaeda static void *
556*2309Srsmaeda pack_message(int cmd, int flags, int count, void *data, size_t *osize)
557*2309Srsmaeda {
558*2309Srsmaeda 	drd_msg_t *msgp;
559*2309Srsmaeda 	size_t hdr_size = offsetof(drd_msg_t, data);
560*2309Srsmaeda 
561*2309Srsmaeda 	switch (cmd) {
562*2309Srsmaeda 	case DRCTL_CPU_CONFIG_REQUEST:
563*2309Srsmaeda 	case DRCTL_CPU_CONFIG_NOTIFY:
564*2309Srsmaeda 	case DRCTL_CPU_UNCONFIG_REQUEST:
565*2309Srsmaeda 	case DRCTL_CPU_UNCONFIG_NOTIFY:
566*2309Srsmaeda 
567*2309Srsmaeda 		*osize = hdr_size + count * sizeof (drctl_rsrc_t);
568*2309Srsmaeda 
569*2309Srsmaeda 		msgp = kmem_alloc(*osize, KM_SLEEP);
570*2309Srsmaeda 		msgp->cmd = cmd;
571*2309Srsmaeda 		msgp->count = count;
572*2309Srsmaeda 		msgp->flags = flags;
573*2309Srsmaeda 		bcopy(data, msgp->data, count * sizeof (drctl_rsrc_t));
574*2309Srsmaeda 		break;
575*2309Srsmaeda 	default:
576*2309Srsmaeda 		cmn_err(CE_WARN,
577*2309Srsmaeda 		    "drctl: pack_message received invalid cmd %d", cmd);
578*2309Srsmaeda 		msgp = NULL;
579*2309Srsmaeda 	}
580*2309Srsmaeda 
581*2309Srsmaeda 	return (msgp);
582*2309Srsmaeda }
583