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  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
     23  * Use is subject to license terms.
     24  */
     25 
     26 
     27 /*
     28  * sun4v domain services PRI driver
     29  */
     30 
     31 #include <sys/types.h>
     32 #include <sys/file.h>
     33 #include <sys/errno.h>
     34 #include <sys/open.h>
     35 #include <sys/cred.h>
     36 #include <sys/uio.h>
     37 #include <sys/stat.h>
     38 #include <sys/ksynch.h>
     39 #include <sys/modctl.h>
     40 #include <sys/conf.h>
     41 #include <sys/devops.h>
     42 #include <sys/debug.h>
     43 #include <sys/cmn_err.h>
     44 #include <sys/ddi.h>
     45 #include <sys/sunddi.h>
     46 #include <sys/ds.h>
     47 
     48 #include <sys/ds_pri.h>
     49 
     50 static uint_t ds_pri_debug = 0;
     51 #define	DS_PRI_DBG	if (ds_pri_debug) printf
     52 
     53 #define	DS_PRI_NAME	"ds_pri"
     54 
     55 #define	TEST_HARNESS
     56 #ifdef TEST_HARNESS
     57 #define	DS_PRI_MAX_PRI_SIZE	(64 * 1024)
     58 
     59 #define	DSIOC_TEST_REG	97
     60 #define	DSIOC_TEST_UNREG	98
     61 #define	DSIOC_TEST_DATA	99
     62 
     63 struct ds_pri_test_data {
     64 	size_t		size;
     65 	void		*data;
     66 };
     67 
     68 struct ds_pri_test_data32 {
     69 	size32_t	size;
     70 	caddr32_t	data;
     71 };
     72 #endif /* TEST_HARNESS */
     73 
     74 typedef	enum {
     75 	DS_PRI_REQUEST	= 0,
     76 	DS_PRI_DATA	= 1,
     77 	DS_PRI_UPDATE	= 2
     78 } ds_pri_msg_type_t;
     79 
     80 typedef	struct {
     81 	struct {
     82 		uint64_t	seq_num;
     83 		uint64_t	type;
     84 	} hdr;
     85 	uint8_t		data[1];
     86 } ds_pri_msg_t;
     87 
     88 	/* The following are bit field flags */
     89 	/* No service implies no PRI and no outstanding request */
     90 typedef enum {
     91 	DS_PRI_NO_SERVICE = 0x0,
     92 	DS_PRI_HAS_SERVICE = 0x1,
     93 	DS_PRI_REQUESTED = 0x2,
     94 	DS_PRI_HAS_PRI = 0x4
     95 } ds_pri_flags_t;
     96 
     97 struct ds_pri_state {
     98 	dev_info_t	*dip;
     99 	int		instance;
    100 
    101 	kmutex_t	lock;
    102 	kcondvar_t	cv;
    103 
    104 	/* PRI/DS */
    105 	ds_pri_flags_t	state;
    106 	uint64_t	gencount;
    107 	ds_svc_hdl_t	ds_pri_handle;
    108 	void		*ds_pri;
    109 	size_t		ds_pri_len;
    110 	uint64_t	req_id;
    111 	uint64_t	last_req_id;
    112 	int		num_opens;
    113 };
    114 
    115 typedef struct ds_pri_state ds_pri_state_t;
    116 
    117 static void *ds_pri_statep;
    118 
    119 static void request_pri(ds_pri_state_t *sp);
    120 
    121 static int ds_pri_getinfo(dev_info_t *, ddi_info_cmd_t, void *, void **);
    122 static int ds_pri_attach(dev_info_t *, ddi_attach_cmd_t);
    123 static int ds_pri_detach(dev_info_t *, ddi_detach_cmd_t);
    124 static int ds_pri_open(dev_t *, int, int, cred_t *);
    125 static int ds_pri_close(dev_t, int, int, cred_t *);
    126 static int ds_pri_read(dev_t, struct uio *, cred_t *);
    127 static int ds_pri_ioctl(dev_t, int, intptr_t, int, cred_t *, int *);
    128 
    129 /*
    130  * DS Callbacks
    131  */
    132 static void ds_pri_reg_handler(ds_cb_arg_t, ds_ver_t *, ds_svc_hdl_t);
    133 static void ds_pri_unreg_handler(ds_cb_arg_t arg);
    134 static void ds_pri_data_handler(ds_cb_arg_t arg, void *buf, size_t buflen);
    135 
    136 /*
    137  * PRI DS capability registration
    138  */
    139 
    140 static ds_ver_t ds_pri_ver_1_0 = { 1, 0 };
    141 
    142 static ds_capability_t ds_pri_cap = {
    143 	"pri",
    144 	&ds_pri_ver_1_0,
    145 	1
    146 };
    147 
    148 /*
    149  * PRI DS Client callback vector
    150  */
    151 static ds_clnt_ops_t ds_pri_ops = {
    152 	ds_pri_reg_handler,	/* ds_reg_cb */
    153 	ds_pri_unreg_handler,	/* ds_unreg_cb */
    154 	ds_pri_data_handler,	/* ds_data_cb */
    155 	NULL			/* cb_arg */
    156 };
    157 
    158 /*
    159  * DS PRI driver Ops Vector
    160  */
    161 static struct cb_ops ds_pri_cb_ops = {
    162 	ds_pri_open,		/* cb_open */
    163 	ds_pri_close,		/* cb_close */
    164 	nodev,			/* cb_strategy */
    165 	nodev,			/* cb_print */
    166 	nodev,			/* cb_dump */
    167 	ds_pri_read,		/* cb_read */
    168 	nodev,			/* cb_write */
    169 	ds_pri_ioctl,		/* cb_ioctl */
    170 	nodev,			/* cb_devmap */
    171 	nodev,			/* cb_mmap */
    172 	nodev,			/* cb_segmap */
    173 	nochpoll,		/* cb_chpoll */
    174 	ddi_prop_op,		/* cb_prop_op */
    175 	(struct streamtab *)NULL, /* cb_str */
    176 	D_MP | D_64BIT,		/* cb_flag */
    177 	CB_REV,			/* cb_rev */
    178 	nodev,			/* cb_aread */
    179 	nodev			/* cb_awrite */
    180 };
    181 
    182 static struct dev_ops ds_pri_dev_ops = {
    183 	DEVO_REV,		/* devo_rev */
    184 	0,			/* devo_refcnt */
    185 	ds_pri_getinfo,		/* devo_getinfo */
    186 	nulldev,		/* devo_identify */
    187 	nulldev,		/* devo_probe */
    188 	ds_pri_attach,		/* devo_attach */
    189 	ds_pri_detach,		/* devo_detach */
    190 	nodev,			/* devo_reset */
    191 	&ds_pri_cb_ops,		/* devo_cb_ops */
    192 	(struct bus_ops *)NULL,	/* devo_bus_ops */
    193 	nulldev,		/* devo_power */
    194 	ddi_quiesce_not_needed,		/* devo_quiesce */
    195 };
    196 
    197 static struct modldrv modldrv = {
    198 	&mod_driverops,
    199 	"Domain Services PRI Driver",
    200 	&ds_pri_dev_ops
    201 };
    202 
    203 static struct modlinkage modlinkage = {
    204 	MODREV_1,
    205 	(void *)&modldrv,
    206 	NULL
    207 };
    208 
    209 
    210 int
    211 _init(void)
    212 {
    213 	int retval;
    214 
    215 	retval = ddi_soft_state_init(&ds_pri_statep,
    216 	    sizeof (ds_pri_state_t), 0);
    217 	if (retval != 0)
    218 		return (retval);
    219 
    220 	retval = mod_install(&modlinkage);
    221 	if (retval != 0) {
    222 		ddi_soft_state_fini(&ds_pri_statep);
    223 		return (retval);
    224 	}
    225 
    226 	return (retval);
    227 }
    228 
    229 
    230 int
    231 _info(struct modinfo *modinfop)
    232 {
    233 	return (mod_info(&modlinkage, modinfop));
    234 }
    235 
    236 
    237 int
    238 _fini(void)
    239 {
    240 	int retval;
    241 
    242 	if ((retval = mod_remove(&modlinkage)) != 0)
    243 		return (retval);
    244 
    245 	ddi_soft_state_fini(&ds_pri_statep);
    246 
    247 	return (retval);
    248 }
    249 
    250 
    251 /*ARGSUSED*/
    252 static int
    253 ds_pri_getinfo(dev_info_t *dip, ddi_info_cmd_t cmd, void *arg, void **resultp)
    254 {
    255 	ds_pri_state_t *sp;
    256 	int retval = DDI_FAILURE;
    257 
    258 	ASSERT(resultp != NULL);
    259 
    260 	switch (cmd) {
    261 	case DDI_INFO_DEVT2DEVINFO:
    262 		sp = ddi_get_soft_state(ds_pri_statep, getminor((dev_t)arg));
    263 		if (sp != NULL) {
    264 			*resultp = sp->dip;
    265 			retval = DDI_SUCCESS;
    266 		} else
    267 			*resultp = NULL;
    268 		break;
    269 
    270 	case DDI_INFO_DEVT2INSTANCE:
    271 		*resultp = (void *)(uintptr_t)getminor((dev_t)arg);
    272 		retval = DDI_SUCCESS;
    273 		break;
    274 
    275 	default:
    276 		break;
    277 	}
    278 
    279 	return (retval);
    280 }
    281 
    282 
    283 static int
    284 ds_pri_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
    285 {
    286 	int instance;
    287 	ds_pri_state_t *sp;
    288 	int rv;
    289 
    290 	switch (cmd) {
    291 	case DDI_ATTACH:
    292 		break;
    293 
    294 	case DDI_RESUME:
    295 		return (DDI_SUCCESS);
    296 
    297 	default:
    298 		return (DDI_FAILURE);
    299 	}
    300 
    301 	instance = ddi_get_instance(dip);
    302 
    303 	if (ddi_soft_state_zalloc(ds_pri_statep, instance) !=
    304 	    DDI_SUCCESS) {
    305 		cmn_err(CE_WARN, "%s@%d: Unable to allocate state",
    306 		    DS_PRI_NAME, instance);
    307 		return (DDI_FAILURE);
    308 	}
    309 	sp = ddi_get_soft_state(ds_pri_statep, instance);
    310 
    311 	mutex_init(&sp->lock, NULL, MUTEX_DEFAULT, NULL);
    312 	cv_init(&sp->cv, NULL, CV_DEFAULT, NULL);
    313 
    314 	if (ddi_create_minor_node(dip, DS_PRI_NAME, S_IFCHR, instance,
    315 	    DDI_PSEUDO, 0) != DDI_SUCCESS) {
    316 		cmn_err(CE_WARN, "%s@%d: Unable to create minor node",
    317 		    DS_PRI_NAME, instance);
    318 		goto fail;
    319 	}
    320 
    321 	if (ds_pri_ops.cb_arg != NULL)
    322 		goto fail;
    323 	ds_pri_ops.cb_arg = dip;
    324 
    325 	sp->state = DS_PRI_NO_SERVICE;
    326 
    327 	/* Until the service registers the handle is invalid */
    328 	sp->ds_pri_handle = DS_INVALID_HDL;
    329 
    330 	sp->ds_pri = NULL;
    331 	sp->ds_pri_len = 0;
    332 	sp->req_id = 0;
    333 	sp->num_opens = 0;
    334 
    335 	if ((rv = ds_cap_init(&ds_pri_cap, &ds_pri_ops)) != 0) {
    336 		cmn_err(CE_NOTE, "ds_cap_init failed: %d", rv);
    337 		goto fail;
    338 	}
    339 
    340 	ddi_report_dev(dip);
    341 
    342 	return (DDI_SUCCESS);
    343 
    344 fail:
    345 	ddi_remove_minor_node(dip, NULL);
    346 	cv_destroy(&sp->cv);
    347 	mutex_destroy(&sp->lock);
    348 	ddi_soft_state_free(ds_pri_statep, instance);
    349 	return (DDI_FAILURE);
    350 
    351 }
    352 
    353 
    354 /*ARGSUSED*/
    355 static int
    356 ds_pri_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
    357 {
    358 	ds_pri_state_t *sp;
    359 	int instance;
    360 	int rv;
    361 
    362 	instance = ddi_get_instance(dip);
    363 	sp = ddi_get_soft_state(ds_pri_statep, instance);
    364 
    365 	switch (cmd) {
    366 	case DDI_DETACH:
    367 		break;
    368 
    369 	case DDI_SUSPEND:
    370 		return (DDI_SUCCESS);
    371 
    372 	default:
    373 		return (DDI_FAILURE);
    374 	}
    375 
    376 	/* This really shouldn't fail - but check anyway */
    377 	if ((rv = ds_cap_fini(&ds_pri_cap)) != 0) {
    378 		cmn_err(CE_WARN, "ds_cap_fini failed: %d", rv);
    379 	}
    380 
    381 	if (sp != NULL && sp->ds_pri_len != 0)
    382 		kmem_free(sp->ds_pri, sp->ds_pri_len);
    383 
    384 	ds_pri_ops.cb_arg = NULL;
    385 
    386 	ddi_remove_minor_node(dip, NULL);
    387 	cv_destroy(&sp->cv);
    388 	mutex_destroy(&sp->lock);
    389 	ddi_soft_state_free(ds_pri_statep, instance);
    390 
    391 	return (DDI_SUCCESS);
    392 }
    393 
    394 
    395 /*ARGSUSED*/
    396 static int
    397 ds_pri_open(dev_t *devp, int flag, int otyp, cred_t *credp)
    398 {
    399 	ds_pri_state_t *sp;
    400 	int instance;
    401 
    402 	if (otyp != OTYP_CHR)
    403 		return (EINVAL);
    404 
    405 	instance = getminor(*devp);
    406 	sp = ddi_get_soft_state(ds_pri_statep, instance);
    407 	if (sp == NULL)
    408 		return (ENXIO);
    409 
    410 	mutex_enter(&sp->lock);
    411 
    412 	/*
    413 	 * If we're here and the state is DS_PRI_NO_SERVICE then this
    414 	 * means that ds hasn't yet called the registration callback.
    415 	 * A while loop is necessary as we might have been woken up
    416 	 * prematurely, e.g., due to a debugger or "pstack" etc.
    417 	 * Wait here and the callback will signal us when it has completed
    418 	 * its work.
    419 	 */
    420 	while (sp->state == DS_PRI_NO_SERVICE) {
    421 		if (cv_wait_sig(&sp->cv, &sp->lock) == 0) {
    422 			mutex_exit(&sp->lock);
    423 			return (EINTR);
    424 		}
    425 	}
    426 
    427 	sp->num_opens++;
    428 	mutex_exit(&sp->lock);
    429 
    430 	/*
    431 	 * On open we dont fetch the PRI even if we have a valid service
    432 	 * handle. PRI fetch is essentially lazy and on-demand.
    433 	 */
    434 
    435 	DS_PRI_DBG("ds_pri_open: state = 0x%x\n", sp->state);
    436 
    437 	return (0);
    438 }
    439 
    440 
    441 /*ARGSUSED*/
    442 static int
    443 ds_pri_close(dev_t dev, int flag, int otyp, cred_t *credp)
    444 {
    445 	int instance;
    446 	ds_pri_state_t *sp;
    447 
    448 	if (otyp != OTYP_CHR)
    449 		return (EINVAL);
    450 
    451 	DS_PRI_DBG("ds_pri_close\n");
    452 
    453 	instance = getminor(dev);
    454 	if ((sp = ddi_get_soft_state(ds_pri_statep, instance)) == NULL)
    455 		return (ENXIO);
    456 
    457 	mutex_enter(&sp->lock);
    458 	if (!(sp->state & DS_PRI_HAS_SERVICE)) {
    459 		mutex_exit(&sp->lock);
    460 		return (0);
    461 	}
    462 
    463 	if (--sp->num_opens > 0) {
    464 		mutex_exit(&sp->lock);
    465 		return (0);
    466 	}
    467 
    468 	/* If we have an old PRI - remove it */
    469 	if (sp->state & DS_PRI_HAS_PRI) {
    470 		if (sp->ds_pri != NULL && sp->ds_pri_len > 0) {
    471 			/*
    472 			 * remove the old data if we have an
    473 			 * outstanding request
    474 			 */
    475 			kmem_free(sp->ds_pri, sp->ds_pri_len);
    476 			sp->ds_pri_len = 0;
    477 			sp->ds_pri = NULL;
    478 		}
    479 		sp->state &= ~DS_PRI_HAS_PRI;
    480 	}
    481 	sp->state &= ~DS_PRI_REQUESTED;
    482 	mutex_exit(&sp->lock);
    483 	return (0);
    484 }
    485 
    486 
    487 /*ARGSUSED*/
    488 static int
    489 ds_pri_read(dev_t dev, struct uio *uiop, cred_t *credp)
    490 {
    491 	ds_pri_state_t *sp;
    492 	int instance;
    493 	size_t len;
    494 	int retval;
    495 	caddr_t tmpbufp;
    496 	offset_t off = uiop->uio_offset;
    497 
    498 	instance = getminor(dev);
    499 	if ((sp = ddi_get_soft_state(ds_pri_statep, instance)) == NULL)
    500 		return (ENXIO);
    501 
    502 	len = uiop->uio_resid;
    503 
    504 	if (len == 0)
    505 		return (0);
    506 
    507 	mutex_enter(&sp->lock);
    508 
    509 	DS_PRI_DBG("ds_pri_read: state = 0x%x\n", sp->state);
    510 
    511 	/* block or bail if there is no current PRI */
    512 	if (!(sp->state & DS_PRI_HAS_PRI)) {
    513 		DS_PRI_DBG("ds_pri_read: no PRI held\n");
    514 
    515 		if (uiop->uio_fmode & (FNDELAY | FNONBLOCK)) {
    516 			mutex_exit(&sp->lock);
    517 			return (EAGAIN);
    518 		}
    519 
    520 		while (!(sp->state & DS_PRI_HAS_PRI)) {
    521 			DS_PRI_DBG("ds_pri_read: state = 0x%x\n", sp->state);
    522 			request_pri(sp);
    523 			if (cv_wait_sig(&sp->cv, &sp->lock) == 0) {
    524 				mutex_exit(&sp->lock);
    525 				return (EINTR);
    526 			}
    527 		}
    528 	}
    529 
    530 	if (len > sp->ds_pri_len)
    531 		len = sp->ds_pri_len;
    532 
    533 	if (len == 0) {
    534 		mutex_exit(&sp->lock);
    535 		return (0);
    536 	}
    537 
    538 	/*
    539 	 * We're supposed to move the data out to userland, but
    540 	 * that can suspend because of page faults etc., and meanwhile
    541 	 * other parts of this driver want to update the PRI buffer ...
    542 	 * we could hold the data buffer locked with a flag etc.,
    543 	 * but that's still a lock ... a simpler mechanism - if not quite
    544 	 * as performance efficient is to simply clone here the part of
    545 	 * the buffer we care about and then the original can be released
    546 	 * for further updates while the uiomove continues.
    547 	 */
    548 
    549 	tmpbufp = kmem_alloc(len, KM_SLEEP);
    550 	bcopy(((caddr_t)sp->ds_pri), tmpbufp, len);
    551 	mutex_exit(&sp->lock);
    552 
    553 	retval = uiomove(tmpbufp, len, UIO_READ, uiop);
    554 
    555 	kmem_free(tmpbufp, len);
    556 
    557 	/*
    558 	 * restore uio_offset after uiomove since the driver
    559 	 * does not support the concept of position.
    560 	 */
    561 	uiop->uio_offset = off;
    562 
    563 	return (retval);
    564 }
    565 
    566 
    567 /*ARGSUSED*/
    568 static int
    569 ds_pri_ioctl(dev_t dev, int cmd, intptr_t arg, int mode, cred_t *credp,
    570     int *rvalp)
    571 {
    572 	ds_pri_state_t *sp;
    573 	int instance;
    574 
    575 	instance = getminor(dev);
    576 	if ((sp = ddi_get_soft_state(ds_pri_statep, instance)) == NULL)
    577 		return (ENXIO);
    578 
    579 	switch (cmd) {
    580 	case DSPRI_GETINFO: {
    581 		struct dspri_info info;
    582 
    583 		if (!(mode & FREAD))
    584 			return (EACCES);
    585 
    586 		/*
    587 		 * We are not guaranteed that ddi_copyout(9F) will read
    588 		 * atomically anything larger than a byte.  Therefore we
    589 		 * must duplicate the size before copying it out to the user.
    590 		 */
    591 		mutex_enter(&sp->lock);
    592 
    593 loop:;
    594 		if (sp->state & DS_PRI_HAS_PRI) {
    595 			/* If we have a PRI simply return the info */
    596 			info.size = sp->ds_pri_len;
    597 			info.token = sp->gencount;
    598 		} else
    599 		if (!(sp->state & DS_PRI_HAS_SERVICE)) {
    600 			/* If we have no service return a nil response */
    601 			info.size = 0;
    602 			info.token = 0;
    603 		} else {
    604 			request_pri(sp);
    605 			/* wait for something & check again */
    606 			if (cv_wait_sig(&sp->cv, &sp->lock) == 0) {
    607 				mutex_exit(&sp->lock);
    608 				return (EINTR);
    609 			}
    610 			goto loop;
    611 		}
    612 		DS_PRI_DBG("ds_pri_ioctl: DSPRI_GETINFO sz=0x%lx tok=0x%lx\n",
    613 		    info.size, info.token);
    614 		mutex_exit(&sp->lock);
    615 
    616 		if (ddi_copyout(&info, (void *)arg, sizeof (info), mode) != 0)
    617 			return (EFAULT);
    618 		break;
    619 	}
    620 
    621 	case DSPRI_WAIT: {
    622 		uint64_t gencount;
    623 
    624 		if (ddi_copyin((void *)arg, &gencount, sizeof (gencount),
    625 		    mode) != 0)
    626 			return (EFAULT);
    627 
    628 		mutex_enter(&sp->lock);
    629 
    630 		DS_PRI_DBG("ds_pri_ioctl: DSPRI_WAIT gen=0x%lx sp->gen=0x%lx\n",
    631 		    gencount, sp->gencount);
    632 
    633 		while ((sp->state & DS_PRI_HAS_PRI) == 0 ||
    634 		    gencount == sp->gencount) {
    635 			if ((sp->state & DS_PRI_HAS_PRI) == 0)
    636 				request_pri(sp);
    637 			if (cv_wait_sig(&sp->cv, &sp->lock) == 0) {
    638 				mutex_exit(&sp->lock);
    639 				return (EINTR);
    640 			}
    641 		}
    642 		mutex_exit(&sp->lock);
    643 		break;
    644 	}
    645 
    646 	default:
    647 		return (ENOTTY);
    648 	}
    649 	return (0);
    650 }
    651 
    652 
    653 	/* assumes sp->lock is held when called */
    654 static void
    655 request_pri(ds_pri_state_t *sp)
    656 {
    657 	ds_pri_msg_t reqmsg;
    658 
    659 	ASSERT(MUTEX_HELD(&sp->lock));
    660 
    661 	/* If a request is already pending we're done */
    662 	if (!(sp->state & DS_PRI_HAS_SERVICE))
    663 		return;
    664 	if (sp->state & DS_PRI_REQUESTED)
    665 		return;
    666 
    667 	/* If we have an old PRI - remove it */
    668 	if (sp->state & DS_PRI_HAS_PRI) {
    669 		ASSERT(sp->ds_pri_len != 0);
    670 		ASSERT(sp->ds_pri != NULL);
    671 
    672 		/* remove the old data if we have an outstanding request */
    673 		kmem_free(sp->ds_pri, sp->ds_pri_len);
    674 		sp->ds_pri_len = 0;
    675 		sp->ds_pri = NULL;
    676 		sp->state &= ~DS_PRI_HAS_PRI;
    677 	} else {
    678 		ASSERT(sp->ds_pri == NULL);
    679 		ASSERT(sp->ds_pri_len == 0);
    680 	}
    681 
    682 	reqmsg.hdr.seq_num = ++(sp->req_id);
    683 	reqmsg.hdr.type = DS_PRI_REQUEST;
    684 
    685 	DS_PRI_DBG("request_pri: request id 0x%lx\n", sp->req_id);
    686 
    687 		/*
    688 		 * Request consists of header only.
    689 		 * We don't care about fail status for ds_send;
    690 		 * if it does fail we will get an unregister callback
    691 		 * from the DS framework and we handle the state change
    692 		 * there.
    693 		 */
    694 	(void) ds_cap_send(sp->ds_pri_handle, &reqmsg, sizeof (reqmsg.hdr));
    695 
    696 	sp->state |= DS_PRI_REQUESTED;
    697 	sp->last_req_id = sp->req_id;
    698 }
    699 
    700 /*
    701  * DS Callbacks
    702  */
    703 /*ARGSUSED*/
    704 static void
    705 ds_pri_reg_handler(ds_cb_arg_t arg, ds_ver_t *ver, ds_svc_hdl_t hdl)
    706 {
    707 	dev_info_t *dip = arg;
    708 	ds_pri_state_t *sp;
    709 	int instance;
    710 
    711 	instance = ddi_get_instance(dip);
    712 	if ((sp = ddi_get_soft_state(ds_pri_statep, instance)) == NULL)
    713 		return;
    714 
    715 	DS_PRI_DBG("ds_pri_reg_handler: registering handle 0x%lx for version "
    716 	    "0x%x:0x%x\n", (uint64_t)hdl, ver->major, ver->minor);
    717 
    718 	/* When the domain service comes up automatically req the pri */
    719 	mutex_enter(&sp->lock);
    720 
    721 	ASSERT(sp->ds_pri_handle == DS_INVALID_HDL);
    722 	sp->ds_pri_handle = hdl;
    723 
    724 	ASSERT(sp->state == DS_PRI_NO_SERVICE);
    725 	ASSERT(sp->ds_pri == NULL);
    726 	ASSERT(sp->ds_pri_len == 0);
    727 
    728 	/* have service, but no PRI */
    729 	sp->state |= DS_PRI_HAS_SERVICE;
    730 
    731 	/*
    732 	 * Cannot request a PRI here, because the reg handler cannot
    733 	 * do a DS send operation - we take care of this later.
    734 	 */
    735 
    736 	/* Wake up anyone waiting in open() */
    737 	cv_broadcast(&sp->cv);
    738 
    739 	mutex_exit(&sp->lock);
    740 }
    741 
    742 
    743 static void
    744 ds_pri_unreg_handler(ds_cb_arg_t arg)
    745 {
    746 	dev_info_t *dip = arg;
    747 	ds_pri_state_t *sp;
    748 	int instance;
    749 
    750 	instance = ddi_get_instance(dip);
    751 	if ((sp = ddi_get_soft_state(ds_pri_statep, instance)) == NULL)
    752 		return;
    753 
    754 	DS_PRI_DBG("ds_pri_unreg_handler: un-registering ds_pri service\n");
    755 
    756 	mutex_enter(&sp->lock);
    757 
    758 	/* Once the service goes - if we have a PRI at hand free it up */
    759 	if (sp->ds_pri_len != 0) {
    760 		kmem_free(sp->ds_pri, sp->ds_pri_len);
    761 		sp->ds_pri_len = 0;
    762 		sp->ds_pri = NULL;
    763 	}
    764 	sp->ds_pri_handle = DS_INVALID_HDL;
    765 	sp->state = DS_PRI_NO_SERVICE;
    766 
    767 	mutex_exit(&sp->lock);
    768 }
    769 
    770 
    771 static void
    772 ds_pri_data_handler(ds_cb_arg_t arg, void *buf, size_t buflen)
    773 {
    774 	dev_info_t *dip = arg;
    775 	ds_pri_state_t *sp;
    776 	int instance;
    777 	void *data;
    778 	ds_pri_msg_t	*msgp;
    779 	size_t	pri_size;
    780 
    781 	msgp = (ds_pri_msg_t *)buf;
    782 
    783 	/* make sure the header is at least valid */
    784 	if (buflen < sizeof (msgp->hdr))
    785 		return;
    786 
    787 	DS_PRI_DBG("ds_pri_data_handler: msg buf len 0x%lx : type 0x%lx, "
    788 	    "seqn 0x%lx\n", buflen, msgp->hdr.type, msgp->hdr.seq_num);
    789 
    790 	instance = ddi_get_instance(dip);
    791 	if ((sp = ddi_get_soft_state(ds_pri_statep, instance)) == NULL)
    792 		return;
    793 
    794 	mutex_enter(&sp->lock);
    795 
    796 	ASSERT(sp->state & DS_PRI_HAS_SERVICE);
    797 
    798 	switch (msgp->hdr.type) {
    799 	case DS_PRI_DATA:	/* in response to a request from us */
    800 		break;
    801 	case DS_PRI_UPDATE:	/* aynch notification */
    802 			/* our default response to this is to request the PRI */
    803 		/* simply issue a request for the new PRI */
    804 		request_pri(sp);
    805 		goto done;
    806 	default:	/* ignore garbage or unknown message types */
    807 		goto done;
    808 	}
    809 
    810 	/*
    811 	 * If there is no pending PRI request, then we've received a
    812 	 * bogus data message ... so ignore it.
    813 	 */
    814 
    815 	if (!(sp->state & DS_PRI_REQUESTED)) {
    816 		cmn_err(CE_WARN, "Received DS pri data without request");
    817 		goto done;
    818 	}
    819 
    820 	/* response to a request therefore old PRI must be gone */
    821 	ASSERT(!(sp->state & DS_PRI_HAS_PRI));
    822 	ASSERT(sp->ds_pri_len == 0);
    823 	ASSERT(sp->ds_pri == NULL);
    824 
    825 	/* response seq_num should match our request seq_num */
    826 	if (msgp->hdr.seq_num != sp->last_req_id) {
    827 		cmn_err(CE_WARN, "Received DS pri data out of sequence with "
    828 		    "request");
    829 		goto done;
    830 	}
    831 
    832 	pri_size = buflen - sizeof (msgp->hdr);
    833 	data = kmem_alloc(pri_size, KM_SLEEP);
    834 	sp->ds_pri = data;
    835 	sp->ds_pri_len = pri_size;
    836 	bcopy(msgp->data, data, sp->ds_pri_len);
    837 	sp->state &= ~DS_PRI_REQUESTED;
    838 	sp->state |= DS_PRI_HAS_PRI;
    839 
    840 	sp->gencount++;
    841 	cv_broadcast(&sp->cv);
    842 
    843 done:;
    844 	mutex_exit(&sp->lock);
    845 }
    846