Home | History | Annotate | Download | only in io
      1 /*
      2  * CDDL HEADER START
      3  *
      4  * The contents of this file are subject to the terms of the
      5  * Common Development and Distribution License (the "License").
      6  * You may not use this file except in compliance with the License.
      7  *
      8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
      9  * or http://www.opensolaris.org/os/licensing.
     10  * See the License for the specific language governing permissions
     11  * and limitations under the License.
     12  *
     13  * When distributing Covered Code, include this CDDL HEADER in each
     14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
     15  * If applicable, add the following below this CDDL HEADER, with the
     16  * fields enclosed by brackets "[]" replaced with your own identifying
     17  * information: Portions Copyright [yyyy] [name of copyright owner]
     18  *
     19  * CDDL HEADER END
     20  */
     21 
     22 /*
     23  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
     24  * Use is subject to license terms.
     25  */
     26 
     27 /*
     28  * DR control module for LDoms
     29  */
     30 
     31 #include <sys/sysmacros.h>
     32 #include <sys/modctl.h>
     33 #include <sys/conf.h>
     34 #include <sys/ddi.h>
     35 #include <sys/sunddi.h>
     36 #include <sys/ddi_impldefs.h>
     37 #include <sys/stat.h>
     38 #include <sys/door.h>
     39 #include <sys/open.h>
     40 #include <sys/note.h>
     41 #include <sys/ldoms.h>
     42 #include <sys/dr_util.h>
     43 #include <sys/drctl.h>
     44 #include <sys/drctl_impl.h>
     45 
     46 
     47 static int drctl_attach(dev_info_t *, ddi_attach_cmd_t);
     48 static int drctl_detach(dev_info_t *, ddi_detach_cmd_t);
     49 static int drctl_getinfo(dev_info_t *, ddi_info_cmd_t, void *, void **);
     50 
     51 static int drctl_open(dev_t *, int, int, cred_t *);
     52 static int drctl_close(dev_t, int, int, cred_t *);
     53 static int drctl_ioctl(dev_t, int, intptr_t, int, cred_t *, int *);
     54 
     55 static void *pack_message(int, int, int, void *, size_t *, size_t *);
     56 static int send_message(void *, size_t, drctl_resp_t **, size_t *);
     57 
     58 
     59 /*
     60  * Configuration data structures
     61  */
     62 static struct cb_ops drctl_cb_ops = {
     63 	drctl_open,		/* open */
     64 	drctl_close,		/* close */
     65 	nodev,			/* strategy */
     66 	nodev,			/* print */
     67 	nodev,			/* dump */
     68 	nodev,			/* read */
     69 	nodev,			/* write */
     70 	drctl_ioctl,		/* ioctl */
     71 	nodev,			/* devmap */
     72 	nodev,			/* mmap */
     73 	nodev,			/* segmap */
     74 	nochpoll,		/* poll */
     75 	ddi_prop_op,		/* prop_op */
     76 	NULL,			/* streamtab */
     77 	D_MP | D_NEW,		/* driver compatibility flag */
     78 	CB_REV,			/* cb_ops revision */
     79 	nodev,			/* async read */
     80 	nodev			/* async write */
     81 };
     82 
     83 
     84 static struct dev_ops drctl_ops = {
     85 	DEVO_REV,		/* devo_rev */
     86 	0,			/* refcnt */
     87 	drctl_getinfo,		/* info */
     88 	nulldev,		/* identify */
     89 	nulldev,		/* probe */
     90 	drctl_attach,		/* attach */
     91 	drctl_detach,		/* detach */
     92 	nodev,			/* reset */
     93 	&drctl_cb_ops,		/* driver operations */
     94 	NULL,			/* bus operations */
     95 	NULL,			/* power */
     96 	ddi_quiesce_not_needed,		/* quiesce */
     97 };
     98 
     99 static struct modldrv modldrv = {
    100 	&mod_driverops,		/* type of module - driver */
    101 	"DR Control pseudo driver",
    102 	&drctl_ops
    103 };
    104 
    105 static struct modlinkage modlinkage = {
    106 	MODREV_1,
    107 	&modldrv,
    108 	NULL
    109 };
    110 
    111 
    112 /*
    113  * Locking strategy
    114  *
    115  * One of the reasons for this module's existence is to serialize
    116  * DR requests which might be coming from different sources.  Only
    117  * one operation is allowed to be in progress at any given time.
    118  *
    119  * A single lock word (the 'drc_busy' element below) is NULL
    120  * when there is no operation in progress.  When a client of this
    121  * module initiates an operation it grabs the mutex 'drc_lock' in
    122  * order to examine the lock word ('drc_busy').  If no other
    123  * operation is in progress, the lock word will be NULL.  If so,
    124  * a cookie which uniquely identifies the requestor is stored in
    125  * the lock word, and the mutex is released.  Attempts by other
    126  * clients to initiate an operation will fail.
    127  *
    128  * When the lock-holding client's operation is completed, the
    129  * client will call a "finalize" function in this module, providing
    130  * the cookie passed with the original request.  Since the cookie
    131  * matches, the operation will succeed and the lock word will be
    132  * cleared.  At this point, an new operation may be initiated.
    133  */
    134 
    135 /*
    136  * Driver private data
    137  */
    138 static struct drctl_unit {
    139 	kmutex_t		drc_lock;	/* global driver lock */
    140 	dev_info_t		*drc_dip;	/* dev_info pointer */
    141 	kcondvar_t		drc_busy_cv;	/* block for !busy */
    142 	drctl_cookie_t		drc_busy;	/* NULL if free else a unique */
    143 						/* identifier for caller */
    144 	int			drc_cmd;	/* the cmd underway (or -1) */
    145 	int			drc_flags;	/* saved flag from above cmd */
    146 	int			drc_inst;	/* our single instance */
    147 	uint_t			drc_state;	/* driver state */
    148 } drctl_state;
    149 
    150 static struct drctl_unit *drctlp = &drctl_state;
    151 
    152 int
    153 _init(void)
    154 {
    155 	int rv;
    156 
    157 	drctlp->drc_inst = -1;
    158 	mutex_init(&drctlp->drc_lock, NULL, MUTEX_DRIVER, NULL);
    159 	cv_init(&drctlp->drc_busy_cv, NULL, CV_DRIVER, NULL);
    160 
    161 	if ((rv = mod_install(&modlinkage)) != 0)
    162 		mutex_destroy(&drctlp->drc_lock);
    163 
    164 	return (rv);
    165 }
    166 
    167 
    168 int
    169 _fini(void)
    170 {
    171 	int rv;
    172 
    173 	if ((rv = mod_remove(&modlinkage)) != 0)
    174 		return (rv);
    175 	cv_destroy(&drctlp->drc_busy_cv);
    176 	mutex_destroy(&drctlp->drc_lock);
    177 	return (0);
    178 }
    179 
    180 
    181 int
    182 _info(struct modinfo *modinfop)
    183 {
    184 	return (mod_info(&modlinkage, modinfop));
    185 }
    186 
    187 
    188 /*
    189  * Do the attach work
    190  */
    191 static int
    192 drctl_do_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
    193 {
    194 	_NOTE(ARGUNUSED(cmd))
    195 
    196 	char *str = "drctl_do_attach";
    197 	int retval = DDI_SUCCESS;
    198 
    199 	if (drctlp->drc_inst != -1) {
    200 		cmn_err(CE_WARN, "%s: an instance is already attached!", str);
    201 		return (DDI_FAILURE);
    202 	}
    203 	drctlp->drc_inst = ddi_get_instance(dip);
    204 
    205 	retval = ddi_create_minor_node(dip, "drctl", S_IFCHR,
    206 	    drctlp->drc_inst, DDI_PSEUDO, 0);
    207 	if (retval != DDI_SUCCESS) {
    208 		cmn_err(CE_WARN, "%s: can't create minor node", str);
    209 		drctlp->drc_inst = -1;
    210 		return (retval);
    211 	}
    212 
    213 	drctlp->drc_dip = dip;
    214 	ddi_report_dev(dip);
    215 
    216 	return (retval);
    217 }
    218 
    219 
    220 static int
    221 drctl_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
    222 {
    223 	switch (cmd) {
    224 	case DDI_ATTACH:
    225 		return (drctl_do_attach(dip, cmd));
    226 
    227 	default:
    228 		return (DDI_FAILURE);
    229 	}
    230 }
    231 
    232 
    233 /* ARGSUSED */
    234 static int
    235 drctl_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
    236 {
    237 	switch (cmd) {
    238 	case DDI_DETACH:
    239 		drctlp->drc_inst = -1;
    240 		ddi_remove_minor_node(dip, "drctl");
    241 		return (DDI_SUCCESS);
    242 
    243 	default:
    244 		return (DDI_FAILURE);
    245 	}
    246 }
    247 
    248 static int
    249 drctl_getinfo(dev_info_t *dip, ddi_info_cmd_t cmd, void *arg, void **resultp)
    250 {
    251 	_NOTE(ARGUNUSED(dip, cmd, arg, resultp))
    252 
    253 	return (0);
    254 }
    255 
    256 static int
    257 drctl_open(dev_t *devp, int flag, int otyp, cred_t *cred_p)
    258 {
    259 	_NOTE(ARGUNUSED(devp, flag, cred_p))
    260 
    261 	if (otyp != OTYP_CHR)
    262 		return (EINVAL);
    263 
    264 	return (0);
    265 }
    266 
    267 static int
    268 drctl_close(dev_t dev, int flag, int otyp, cred_t *cred_p)
    269 {
    270 	_NOTE(ARGUNUSED(dev, flag, otyp, cred_p))
    271 
    272 	return (0);
    273 }
    274 
    275 /*
    276  * Create a reponse structure which includes an array of drctl_rsrc_t
    277  * structures in which each status element is set to the 'status'
    278  * arg.  There is no error text, so set the 'offset' elements to 0.
    279  */
    280 static drctl_resp_t *
    281 drctl_generate_resp(drctl_rsrc_t *res,
    282     int count, size_t *rsize, drctl_status_t status)
    283 {
    284 	int		i;
    285 	size_t		size;
    286 	drctl_rsrc_t	*rsrc;
    287 	drctl_resp_t	*resp;
    288 
    289 	size = offsetof(drctl_resp_t, resp_resources) + (count * sizeof (*res));
    290 	resp  = kmem_alloc(size, KM_SLEEP);
    291 	DR_DBG_KMEM("%s: alloc addr %p size %ld\n",
    292 	    __func__, (void *)resp, size);
    293 
    294 	resp->resp_type = DRCTL_RESP_OK;
    295 	rsrc = resp->resp_resources;
    296 
    297 	bcopy(res, rsrc, count * sizeof (*res));
    298 
    299 	for (i = 0; i < count; i++) {
    300 		rsrc[i].status = status;
    301 		rsrc[i].offset = 0;
    302 	}
    303 
    304 	*rsize = size;
    305 
    306 	return (resp);
    307 }
    308 
    309 /*
    310  * Generate an error response message.
    311  */
    312 static drctl_resp_t *
    313 drctl_generate_err_resp(char *msg, size_t *size)
    314 {
    315 	drctl_resp_t	*resp;
    316 
    317 	ASSERT(msg != NULL);
    318 	ASSERT(size != NULL);
    319 
    320 	*size = offsetof(drctl_resp_t, resp_err_msg) + strlen(msg) + 1;
    321 	resp = kmem_alloc(*size, KM_SLEEP);
    322 	DR_DBG_KMEM("%s: alloc addr %p size %ld\n",
    323 	    __func__, (void *)resp, *size);
    324 
    325 	resp->resp_type = DRCTL_RESP_ERR;
    326 	(void) strcpy(resp->resp_err_msg, msg);
    327 
    328 	return (resp);
    329 }
    330 
    331 /*
    332  * Since response comes from userland, verify that it is at least the
    333  * minimum size based on the size of the original request.  Verify
    334  * that any offsets to error strings are within the string area of
    335  * the response and, force the string area to be null-terminated.
    336  */
    337 static int
    338 verify_response(int cmd,
    339     int count, drctl_resp_t *resp, size_t sent_len, size_t resp_len)
    340 {
    341 	drctl_rsrc_t *rsrc = resp->resp_resources;
    342 	size_t rcvd_len = resp_len - (offsetof(drctl_resp_t, resp_resources));
    343 	int is_cpu = 0;
    344 	int i;
    345 
    346 	switch (cmd) {
    347 	case DRCTL_CPU_CONFIG_REQUEST:
    348 	case DRCTL_CPU_UNCONFIG_REQUEST:
    349 		if (rcvd_len < sent_len)
    350 			return (EIO);
    351 		is_cpu = 1;
    352 		break;
    353 	case DRCTL_IO_UNCONFIG_REQUEST:
    354 	case DRCTL_IO_CONFIG_REQUEST:
    355 		if (count != 1)
    356 			return (EIO);
    357 		break;
    358 	case DRCTL_MEM_CONFIG_REQUEST:
    359 	case DRCTL_MEM_UNCONFIG_REQUEST:
    360 		break;
    361 	default:
    362 		return (EIO);
    363 	}
    364 
    365 	for (i = 0; i < count; i++)
    366 		if ((rsrc[i].offset > 0) &&
    367 		    /* string can't be inside the bounds of original request */
    368 		    (((rsrc[i].offset < sent_len) && is_cpu) ||
    369 		    /* string must start inside the message */
    370 		    (rsrc[i].offset >= rcvd_len)))
    371 			return (EIO);
    372 
    373 	/* If there are any strings, terminate the string area. */
    374 	if (rcvd_len > sent_len)
    375 		*((char *)rsrc + rcvd_len - 1) = '\0';
    376 
    377 	return (0);
    378 }
    379 
    380 static int
    381 drctl_config_common(int cmd, int flags, drctl_rsrc_t *res,
    382     int count, drctl_resp_t **rbuf, size_t *rsize, size_t *rq_size)
    383 {
    384 	int	rv = 0;
    385 	size_t	size;
    386 	char	*bufp;
    387 
    388 	switch (cmd) {
    389 	case DRCTL_CPU_CONFIG_REQUEST:
    390 	case DRCTL_CPU_CONFIG_NOTIFY:
    391 	case DRCTL_CPU_UNCONFIG_REQUEST:
    392 	case DRCTL_CPU_UNCONFIG_NOTIFY:
    393 	case DRCTL_IO_UNCONFIG_REQUEST:
    394 	case DRCTL_IO_UNCONFIG_NOTIFY:
    395 	case DRCTL_IO_CONFIG_REQUEST:
    396 	case DRCTL_IO_CONFIG_NOTIFY:
    397 	case DRCTL_MEM_CONFIG_REQUEST:
    398 	case DRCTL_MEM_CONFIG_NOTIFY:
    399 	case DRCTL_MEM_UNCONFIG_REQUEST:
    400 	case DRCTL_MEM_UNCONFIG_NOTIFY:
    401 		rv = 0;
    402 		break;
    403 	default:
    404 		rv = ENOTSUP;
    405 		break;
    406 	}
    407 
    408 	if (rv != 0) {
    409 		DR_DBG_CTL("%s: invalid cmd %d\n", __func__, cmd);
    410 		return (rv);
    411 	}
    412 
    413 	/*
    414 	 * If the operation is a FORCE, we don't send a message to
    415 	 * the daemon.  But, the upstream clients still expect a
    416 	 * response, so generate a response with all ops 'allowed'.
    417 	 */
    418 	if (flags == DRCTL_FLAG_FORCE) {
    419 		if (rbuf != NULL)
    420 			*rbuf = drctl_generate_resp(res,
    421 			    count, rsize, DRCTL_STATUS_ALLOW);
    422 		return (0);
    423 	}
    424 
    425 	bufp = pack_message(cmd, flags, count, (void *)res, &size, rq_size);
    426 	DR_DBG_CTL("%s: from pack_message, bufp = %p size %ld\n",
    427 	    __func__, (void *)bufp, size);
    428 
    429 	if (bufp == NULL || size == 0)
    430 		return (EINVAL);
    431 
    432 	return (send_message(bufp, size, rbuf, rsize));
    433 }
    434 
    435 /*
    436  * Prepare for a reconfig operation.
    437  */
    438 int
    439 drctl_config_init(int cmd, int flags, drctl_rsrc_t *res,
    440     int count, drctl_resp_t **rbuf, size_t *rsize, drctl_cookie_t ck)
    441 {
    442 	static char inval_msg[] = "Invalid command format received.\n";
    443 	static char unsup_msg[] = "Unsuppported command received.\n";
    444 	static char unk_msg  [] = "Failure reason unknown.\n";
    445 	static char rsp_msg  [] = "Invalid response from "
    446 	    "reconfiguration daemon.\n";
    447 	static char drd_msg  [] = "Cannot communicate with reconfiguration "
    448 	    "daemon (drd) in target domain.\n"
    449 	    "drd(1M) SMF service may not be enabled.\n";
    450 	static char busy_msg [] = "Busy executing earlier command; "
    451 	    "please try again later.\n";
    452 	size_t rq_size;
    453 	char *ermsg;
    454 	int rv;
    455 
    456 	if (ck == 0) {
    457 		*rbuf = drctl_generate_err_resp(inval_msg, rsize);
    458 
    459 		return (EINVAL);
    460 	}
    461 
    462 	mutex_enter(&drctlp->drc_lock);
    463 	if (drctlp->drc_busy != NULL) {
    464 		mutex_exit(&drctlp->drc_lock);
    465 		*rbuf = drctl_generate_err_resp(busy_msg, rsize);
    466 
    467 		return (EBUSY);
    468 	}
    469 
    470 	DR_DBG_CTL("%s: cmd %d flags %d res %p count %d\n",
    471 	    __func__, cmd, flags, (void *)res, count);
    472 
    473 	/* Mark the link busy.  Below we will fill in the actual cookie. */
    474 	drctlp->drc_busy = (drctl_cookie_t)-1;
    475 	mutex_exit(&drctlp->drc_lock);
    476 
    477 	rv = drctl_config_common(cmd, flags, res, count, rbuf, rsize, &rq_size);
    478 	if (rv == 0) {
    479 		/*
    480 		 * If the upcall to the daemon returned successfully, we
    481 		 * still need to validate the format of the returned msg.
    482 		 */
    483 		if ((rv = verify_response(cmd,
    484 		    count, *rbuf, rq_size, *rsize)) != 0) {
    485 			DR_DBG_KMEM("%s: free addr %p size %ld\n",
    486 			    __func__, (void *)*rbuf, *rsize);
    487 			kmem_free(*rbuf, *rsize);
    488 			*rbuf = drctl_generate_err_resp(rsp_msg, rsize);
    489 			drctlp->drc_busy = NULL;
    490 			cv_broadcast(&drctlp->drc_busy_cv);
    491 		} else { /* message format is valid */
    492 			drctlp->drc_busy = ck;
    493 			drctlp->drc_cmd = cmd;
    494 			drctlp->drc_flags = flags;
    495 		}
    496 	} else {
    497 		switch (rv) {
    498 		case ENOTSUP:
    499 			ermsg = unsup_msg;
    500 			break;
    501 		case EIO:
    502 			ermsg = drd_msg;
    503 			break;
    504 		default:
    505 			ermsg = unk_msg;
    506 			break;
    507 		}
    508 
    509 		*rbuf = drctl_generate_err_resp(ermsg, rsize);
    510 
    511 		drctlp->drc_cmd = -1;
    512 		drctlp->drc_flags = 0;
    513 		drctlp->drc_busy = NULL;
    514 		cv_broadcast(&drctlp->drc_busy_cv);
    515 	}
    516 	return (rv);
    517 }
    518 
    519 /*
    520  * Complete a reconfig operation.
    521  */
    522 int
    523 drctl_config_fini(drctl_cookie_t ck, drctl_rsrc_t *res, int count)
    524 {
    525 	int rv;
    526 	int notify_cmd;
    527 	int flags;
    528 	size_t rq_size;
    529 
    530 	mutex_enter(&drctlp->drc_lock);
    531 	if (drctlp->drc_busy != ck) {
    532 		mutex_exit(&drctlp->drc_lock);
    533 		return (EBUSY);
    534 	}
    535 	mutex_exit(&drctlp->drc_lock);
    536 
    537 	flags = drctlp->drc_flags;
    538 	/*
    539 	 * Flip the saved _REQUEST command to its corresponding
    540 	 * _NOTIFY command.
    541 	 */
    542 	switch (drctlp->drc_cmd) {
    543 	case DRCTL_CPU_CONFIG_REQUEST:
    544 		notify_cmd = DRCTL_CPU_CONFIG_NOTIFY;
    545 		break;
    546 
    547 	case DRCTL_CPU_UNCONFIG_REQUEST:
    548 		notify_cmd = DRCTL_CPU_UNCONFIG_NOTIFY;
    549 		break;
    550 
    551 	case DRCTL_IO_UNCONFIG_REQUEST:
    552 		notify_cmd = DRCTL_IO_UNCONFIG_NOTIFY;
    553 		break;
    554 
    555 	case DRCTL_IO_CONFIG_REQUEST:
    556 		notify_cmd = DRCTL_IO_CONFIG_NOTIFY;
    557 		break;
    558 
    559 	case DRCTL_MEM_CONFIG_REQUEST:
    560 		notify_cmd = DRCTL_MEM_CONFIG_NOTIFY;
    561 		break;
    562 
    563 	case DRCTL_MEM_UNCONFIG_REQUEST:
    564 		notify_cmd = DRCTL_MEM_UNCONFIG_NOTIFY;
    565 		break;
    566 
    567 	default:
    568 		/* none of the above should have been accepted in _init */
    569 		ASSERT(0);
    570 		cmn_err(CE_CONT,
    571 		    "drctl_config_fini: bad cmd %d\n", drctlp->drc_cmd);
    572 		rv = EINVAL;
    573 		goto done;
    574 	}
    575 
    576 	rv = drctl_config_common(notify_cmd,
    577 	    flags, res, count, NULL, 0, &rq_size);
    578 
    579 done:
    580 		drctlp->drc_cmd = -1;
    581 		drctlp->drc_flags = 0;
    582 		drctlp->drc_busy = NULL;
    583 		cv_broadcast(&drctlp->drc_busy_cv);
    584 		return (rv);
    585 }
    586 
    587 static int
    588 drctl_ioctl(dev_t dev,
    589     int cmd, intptr_t arg, int mode, cred_t *cred_p, int *rval_p)
    590 {
    591 	_NOTE(ARGUNUSED(dev, mode, cred_p, rval_p))
    592 
    593 	int rv;
    594 
    595 	switch (cmd) {
    596 	case DRCTL_IOCTL_CONNECT_SERVER:
    597 		rv = i_drctl_ioctl(cmd, arg);
    598 		break;
    599 	default:
    600 		rv = ENOTSUP;
    601 	}
    602 
    603 	*rval_p = (rv == 0) ? 0 : -1;
    604 
    605 	return (rv);
    606 }
    607 
    608 /*
    609  * Accept a preformatted request from caller and send a message to
    610  * the daemon.  A pointer to the daemon's response buffer is passed
    611  * back in obufp, its size in osize.
    612  */
    613 static int
    614 send_message(void *msg, size_t size, drctl_resp_t **obufp, size_t *osize)
    615 {
    616 	drctl_resp_t *bufp;
    617 	drctl_rsrc_t *rsrcs;
    618 	size_t rsrcs_size;
    619 	int rv;
    620 
    621 	rv = i_drctl_send(msg, size, (void **)&rsrcs, &rsrcs_size);
    622 
    623 	if ((rv == 0) && ((rsrcs == NULL) ||(rsrcs_size == 0)))
    624 		rv = EINVAL;
    625 
    626 	if (rv == 0) {
    627 		if (obufp != NULL) {
    628 			ASSERT(osize != NULL);
    629 
    630 			*osize =
    631 			    offsetof(drctl_resp_t, resp_resources) + rsrcs_size;
    632 			bufp =
    633 			    kmem_alloc(*osize, KM_SLEEP);
    634 			DR_DBG_KMEM("%s: alloc addr %p size %ld\n",
    635 			    __func__, (void *)bufp, *osize);
    636 			bufp->resp_type = DRCTL_RESP_OK;
    637 			bcopy(rsrcs, bufp->resp_resources, rsrcs_size);
    638 			*obufp = bufp;
    639 		}
    640 
    641 		DR_DBG_KMEM("%s: free addr %p size %ld\n",
    642 		    __func__, (void *)rsrcs, rsrcs_size);
    643 		kmem_free(rsrcs, rsrcs_size);
    644 	}
    645 
    646 	DR_DBG_KMEM("%s:free addr %p size %ld\n", __func__, msg, size);
    647 	kmem_free(msg, size);
    648 
    649 	return (rv);
    650 }
    651 
    652 static void *
    653 pack_message(int cmd,
    654     int flags, int count, void *data, size_t *osize, size_t *data_size)
    655 {
    656 	drd_msg_t *msgp = NULL;
    657 	size_t hdr_size = offsetof(drd_msg_t, data);
    658 
    659 	switch (cmd) {
    660 	case DRCTL_CPU_CONFIG_REQUEST:
    661 	case DRCTL_CPU_CONFIG_NOTIFY:
    662 	case DRCTL_CPU_UNCONFIG_REQUEST:
    663 	case DRCTL_CPU_UNCONFIG_NOTIFY:
    664 		*data_size = count * sizeof (drctl_rsrc_t);
    665 		break;
    666 	case DRCTL_MEM_CONFIG_REQUEST:
    667 	case DRCTL_MEM_CONFIG_NOTIFY:
    668 	case DRCTL_MEM_UNCONFIG_REQUEST:
    669 	case DRCTL_MEM_UNCONFIG_NOTIFY:
    670 		*data_size = count * sizeof (drctl_rsrc_t);
    671 		break;
    672 	case DRCTL_IO_CONFIG_REQUEST:
    673 	case DRCTL_IO_CONFIG_NOTIFY:
    674 	case DRCTL_IO_UNCONFIG_REQUEST:
    675 	case DRCTL_IO_UNCONFIG_NOTIFY:
    676 		*data_size = sizeof (drctl_rsrc_t) +
    677 		    strlen(((drctl_rsrc_t *)data)->res_dev_path);
    678 		break;
    679 	default:
    680 		cmn_err(CE_WARN,
    681 		    "drctl: pack_message received invalid cmd %d", cmd);
    682 		break;
    683 	}
    684 
    685 	if (data_size) {
    686 		*osize = hdr_size + *data_size;
    687 		msgp = kmem_alloc(*osize, KM_SLEEP);
    688 		DR_DBG_KMEM("%s: alloc addr %p size %ld\n",
    689 		    __func__, (void *)msgp, *osize);
    690 		msgp->cmd = cmd;
    691 		msgp->count = count;
    692 		msgp->flags = flags;
    693 		bcopy(data, msgp->data, *data_size);
    694 	}
    695 
    696 	return (msgp);
    697 }
    698 
    699 /*
    700  * Block DR operations
    701  */
    702 void
    703 drctl_block(void)
    704 {
    705 	/* Wait for any in progress DR operation to complete */
    706 	mutex_enter(&drctlp->drc_lock);
    707 	while (drctlp->drc_busy != NULL)
    708 		(void) cv_wait_sig(&drctlp->drc_busy_cv, &drctlp->drc_lock);
    709 	/* Mark the link busy */
    710 	drctlp->drc_busy = (drctl_cookie_t)-1;
    711 	drctlp->drc_cmd = DRCTL_DRC_BLOCK;
    712 	drctlp->drc_flags = 0;
    713 	mutex_exit(&drctlp->drc_lock);
    714 }
    715 
    716 /*
    717  * Unblock DR operations
    718  */
    719 void
    720 drctl_unblock(void)
    721 {
    722 	/* Mark the link free */
    723 	mutex_enter(&drctlp->drc_lock);
    724 	drctlp->drc_cmd = -1;
    725 	drctlp->drc_flags = 0;
    726 	drctlp->drc_busy = NULL;
    727 	cv_broadcast(&drctlp->drc_busy_cv);
    728 	mutex_exit(&drctlp->drc_lock);
    729 }
    730