xref: /titanic_41/usr/src/uts/sun4v/io/ds_pri.c (revision b9238976491622ad75a67ab0c12edf99e36212b9)
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 2007 Sun Microsystems, Inc.  All rights reserved.
23  * Use is subject to license terms.
24  */
25 
26 #pragma ident	"%Z%%M%	%I%	%E% SMI"
27 
28 /*
29  * sun4v domain services PRI driver
30  */
31 
32 #include <sys/types.h>
33 #include <sys/file.h>
34 #include <sys/errno.h>
35 #include <sys/open.h>
36 #include <sys/cred.h>
37 #include <sys/uio.h>
38 #include <sys/stat.h>
39 #include <sys/ksynch.h>
40 #include <sys/modctl.h>
41 #include <sys/conf.h>
42 #include <sys/devops.h>
43 #include <sys/debug.h>
44 #include <sys/cmn_err.h>
45 #include <sys/ddi.h>
46 #include <sys/sunddi.h>
47 #include <sys/ds.h>
48 
49 #include <sys/ds_pri.h>
50 
51 static uint_t ds_pri_debug = 0;
52 #define	DS_PRI_DBG	if (ds_pri_debug) printf
53 
54 #define	DS_PRI_NAME	"ds_pri"
55 
56 #define	TEST_HARNESS
57 #ifdef TEST_HARNESS
58 #define	DS_PRI_MAX_PRI_SIZE	(64 * 1024)
59 
60 #define	DSIOC_TEST_REG	97
61 #define	DSIOC_TEST_UNREG	98
62 #define	DSIOC_TEST_DATA	99
63 
64 struct ds_pri_test_data {
65 	size_t		size;
66 	void		*data;
67 };
68 
69 struct ds_pri_test_data32 {
70 	size32_t	size;
71 	caddr32_t	data;
72 };
73 #endif /* TEST_HARNESS */
74 
75 typedef	enum {
76 	DS_PRI_REQUEST	= 0,
77 	DS_PRI_DATA	= 1,
78 	DS_PRI_UPDATE	= 2
79 } ds_pri_msg_type_t;
80 
81 typedef	struct {
82 	struct {
83 		uint64_t	seq_num;
84 		uint64_t	type;
85 	} hdr;
86 	uint8_t		data[1];
87 } ds_pri_msg_t;
88 
89 	/* The following are bit field flags */
90 	/* No service implies no PRI and no outstanding request */
91 typedef enum {
92 	DS_PRI_NO_SERVICE = 0x0,
93 	DS_PRI_HAS_SERVICE = 0x1,
94 	DS_PRI_REQUESTED = 0x2,
95 	DS_PRI_HAS_PRI = 0x4
96 } ds_pri_flags_t;
97 
98 struct ds_pri_state {
99 	dev_info_t	*dip;
100 	int		instance;
101 
102 	kmutex_t	lock;
103 	kcondvar_t	cv;
104 
105 	/* PRI/DS */
106 	ds_pri_flags_t	state;
107 	uint64_t	gencount;
108 	ds_svc_hdl_t	ds_pri_handle;
109 	void		*ds_pri;
110 	size_t		ds_pri_len;
111 	uint64_t	req_id;
112 	uint64_t	last_req_id;
113 	int		num_opens;
114 };
115 
116 typedef struct ds_pri_state ds_pri_state_t;
117 
118 static void *ds_pri_statep;
119 
120 static void request_pri(ds_pri_state_t *sp);
121 
122 static int ds_pri_getinfo(dev_info_t *, ddi_info_cmd_t, void *, void **);
123 static int ds_pri_attach(dev_info_t *, ddi_attach_cmd_t);
124 static int ds_pri_detach(dev_info_t *, ddi_detach_cmd_t);
125 static int ds_pri_open(dev_t *, int, int, cred_t *);
126 static int ds_pri_close(dev_t, int, int, cred_t *);
127 static int ds_pri_read(dev_t, struct uio *, cred_t *);
128 static int ds_pri_ioctl(dev_t, int, intptr_t, int, cred_t *, int *);
129 
130 /*
131  * DS Callbacks
132  */
133 static void ds_pri_reg_handler(ds_cb_arg_t, ds_ver_t *, ds_svc_hdl_t);
134 static void ds_pri_unreg_handler(ds_cb_arg_t arg);
135 static void ds_pri_data_handler(ds_cb_arg_t arg, void *buf, size_t buflen);
136 
137 /*
138  * PRI DS capability registration
139  */
140 
141 static ds_ver_t ds_pri_ver_1_0 = { 1, 0 };
142 
143 static ds_capability_t ds_pri_cap = {
144 	"pri",
145 	&ds_pri_ver_1_0,
146 	1
147 };
148 
149 /*
150  * PRI DS Client callback vector
151  */
152 static ds_clnt_ops_t ds_pri_ops = {
153 	ds_pri_reg_handler,	/* ds_reg_cb */
154 	ds_pri_unreg_handler,	/* ds_unreg_cb */
155 	ds_pri_data_handler,	/* ds_data_cb */
156 	NULL			/* cb_arg */
157 };
158 
159 /*
160  * DS PRI driver Ops Vector
161  */
162 static struct cb_ops ds_pri_cb_ops = {
163 	ds_pri_open,		/* cb_open */
164 	ds_pri_close,		/* cb_close */
165 	nodev,			/* cb_strategy */
166 	nodev,			/* cb_print */
167 	nodev,			/* cb_dump */
168 	ds_pri_read,		/* cb_read */
169 	nodev,			/* cb_write */
170 	ds_pri_ioctl,		/* cb_ioctl */
171 	nodev,			/* cb_devmap */
172 	nodev,			/* cb_mmap */
173 	nodev,			/* cb_segmap */
174 	nochpoll,		/* cb_chpoll */
175 	ddi_prop_op,		/* cb_prop_op */
176 	(struct streamtab *)NULL, /* cb_str */
177 	D_MP | D_64BIT,		/* cb_flag */
178 	CB_REV,			/* cb_rev */
179 	nodev,			/* cb_aread */
180 	nodev			/* cb_awrite */
181 };
182 
183 static struct dev_ops ds_pri_dev_ops = {
184 	DEVO_REV,		/* devo_rev */
185 	0,			/* devo_refcnt */
186 	ds_pri_getinfo,		/* devo_getinfo */
187 	nulldev,		/* devo_identify */
188 	nulldev,		/* devo_probe */
189 	ds_pri_attach,		/* devo_attach */
190 	ds_pri_detach,		/* devo_detach */
191 	nodev,			/* devo_reset */
192 	&ds_pri_cb_ops,		/* devo_cb_ops */
193 	(struct bus_ops *)NULL,	/* devo_bus_ops */
194 	nulldev			/* devo_power */
195 };
196 
197 static struct modldrv modldrv = {
198 	&mod_driverops,
199 	"Domain Services PRI Driver 1.0",
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 
497 	instance = getminor(dev);
498 	if ((sp = ddi_get_soft_state(ds_pri_statep, instance)) == NULL)
499 		return (ENXIO);
500 
501 	len = uiop->uio_resid;
502 
503 	if (len == 0)
504 		return (0);
505 
506 	mutex_enter(&sp->lock);
507 
508 	DS_PRI_DBG("ds_pri_read: state = 0x%x\n", sp->state);
509 
510 	/* block or bail if there is no current PRI */
511 	if (!(sp->state & DS_PRI_HAS_PRI)) {
512 		DS_PRI_DBG("ds_pri_read: no PRI held\n");
513 
514 		if (uiop->uio_fmode & (FNDELAY | FNONBLOCK)) {
515 			mutex_exit(&sp->lock);
516 			return (EAGAIN);
517 		}
518 
519 		while (!(sp->state & DS_PRI_HAS_PRI)) {
520 			DS_PRI_DBG("ds_pri_read: state = 0x%x\n", sp->state);
521 			request_pri(sp);
522 			if (cv_wait_sig(&sp->cv, &sp->lock) == 0) {
523 				mutex_exit(&sp->lock);
524 				return (EINTR);
525 			}
526 		}
527 	}
528 
529 	if (uiop->uio_offset < 0 || uiop->uio_offset > sp->ds_pri_len) {
530 		mutex_exit(&sp->lock);
531 		return (EINVAL);
532 	}
533 
534 	if (len > (sp->ds_pri_len - uiop->uio_offset))
535 		len = sp->ds_pri_len - uiop->uio_offset;
536 
537 	/* already checked that offset < ds_pri_len above */
538 	if (len == 0) {
539 		mutex_exit(&sp->lock);
540 		return (0);
541 	}
542 
543 	/*
544 	 * We're supposed to move the data out to userland, but
545 	 * that can suspend because of page faults etc., and meanwhile
546 	 * other parts of this driver want to update the PRI buffer ...
547 	 * we could hold the data buffer locked with a flag etc.,
548 	 * but that's still a lock ... a simpler mechanism - if not quite
549 	 * as performance efficient is to simply clone here the part of
550 	 * the buffer we care about and then the original can be released
551 	 * for further updates while the uiomove continues.
552 	 */
553 
554 	tmpbufp = kmem_alloc(len, KM_SLEEP);
555 	bcopy(((caddr_t)sp->ds_pri) + uiop->uio_offset, tmpbufp, len);
556 	mutex_exit(&sp->lock);
557 
558 	retval = uiomove(tmpbufp, len, UIO_READ, uiop);
559 
560 	kmem_free(tmpbufp, len);
561 
562 	return (retval);
563 }
564 
565 
566 /*ARGSUSED*/
567 static int
568 ds_pri_ioctl(dev_t dev, int cmd, intptr_t arg, int mode, cred_t *credp,
569     int *rvalp)
570 {
571 	ds_pri_state_t *sp;
572 	int instance;
573 
574 	instance = getminor(dev);
575 	if ((sp = ddi_get_soft_state(ds_pri_statep, instance)) == NULL)
576 		return (ENXIO);
577 
578 	switch (cmd) {
579 	case DSPRI_GETINFO: {
580 		struct dspri_info info;
581 
582 		if (!(mode & FREAD))
583 			return (EACCES);
584 
585 		/*
586 		 * We are not guaranteed that ddi_copyout(9F) will read
587 		 * atomically anything larger than a byte.  Therefore we
588 		 * must duplicate the size before copying it out to the user.
589 		 */
590 		mutex_enter(&sp->lock);
591 
592 loop:;
593 		if (sp->state & DS_PRI_HAS_PRI) {
594 			/* If we have a PRI simply return the info */
595 			info.size = sp->ds_pri_len;
596 			info.token = sp->gencount;
597 		} else
598 		if (!(sp->state & DS_PRI_HAS_SERVICE)) {
599 			/* If we have no service return a nil response */
600 			info.size = 0;
601 			info.token = 0;
602 		} else {
603 			request_pri(sp);
604 			/* wait for something & check again */
605 			if (cv_wait_sig(&sp->cv, &sp->lock) == 0) {
606 				mutex_exit(&sp->lock);
607 				return (EINTR);
608 			}
609 			goto loop;
610 		}
611 		DS_PRI_DBG("ds_pri_ioctl: DSPRI_GETINFO sz=0x%lx tok=0x%lx\n",
612 		    info.size, info.token);
613 		mutex_exit(&sp->lock);
614 
615 		if (ddi_copyout(&info, (void *)arg, sizeof (info), mode) != 0)
616 			return (EFAULT);
617 		break;
618 	}
619 
620 	case DSPRI_WAIT: {
621 		uint64_t gencount;
622 
623 		if (ddi_copyin((void *)arg, &gencount, sizeof (gencount),
624 		    mode) != 0)
625 			return (EFAULT);
626 
627 		mutex_enter(&sp->lock);
628 
629 		DS_PRI_DBG("ds_pri_ioctl: DSPRI_WAIT gen=0x%lx sp->gen=0x%lx\n",
630 		    gencount, sp->gencount);
631 
632 		while ((sp->state & DS_PRI_HAS_PRI) == 0 ||
633 		    gencount == sp->gencount) {
634 			if ((sp->state & DS_PRI_HAS_PRI) == 0)
635 				request_pri(sp);
636 			if (cv_wait_sig(&sp->cv, &sp->lock) == 0) {
637 				mutex_exit(&sp->lock);
638 				return (EINTR);
639 			}
640 		}
641 		mutex_exit(&sp->lock);
642 		break;
643 	}
644 
645 	default:
646 		return (ENOTTY);
647 	}
648 	return (0);
649 }
650 
651 
652 	/* assumes sp->lock is held when called */
653 static void
654 request_pri(ds_pri_state_t *sp)
655 {
656 	ds_pri_msg_t reqmsg;
657 
658 	ASSERT(MUTEX_HELD(&sp->lock));
659 
660 	/* If a request is already pending we're done */
661 	if (!(sp->state & DS_PRI_HAS_SERVICE))
662 		return;
663 	if (sp->state & DS_PRI_REQUESTED)
664 		return;
665 
666 	/* If we have an old PRI - remove it */
667 	if (sp->state & DS_PRI_HAS_PRI) {
668 		ASSERT(sp->ds_pri_len != 0);
669 		ASSERT(sp->ds_pri != NULL);
670 
671 		/* remove the old data if we have an outstanding request */
672 		kmem_free(sp->ds_pri, sp->ds_pri_len);
673 		sp->ds_pri_len = 0;
674 		sp->ds_pri = NULL;
675 		sp->state &= ~DS_PRI_HAS_PRI;
676 	} else {
677 		ASSERT(sp->ds_pri == NULL);
678 		ASSERT(sp->ds_pri_len == 0);
679 	}
680 
681 	reqmsg.hdr.seq_num = ++(sp->req_id);
682 	reqmsg.hdr.type = DS_PRI_REQUEST;
683 
684 	DS_PRI_DBG("request_pri: request id 0x%lx\n", sp->req_id);
685 
686 		/*
687 		 * Request consists of header only.
688 		 * We don't care about fail status for ds_send;
689 		 * if it does fail we will get an unregister callback
690 		 * from the DS framework and we handle the state change
691 		 * there.
692 		 */
693 	(void) ds_cap_send(sp->ds_pri_handle, &reqmsg, sizeof (reqmsg.hdr));
694 
695 	sp->state |= DS_PRI_REQUESTED;
696 	sp->last_req_id = sp->req_id;
697 }
698 
699 /*
700  * DS Callbacks
701  */
702 /*ARGSUSED*/
703 static void
704 ds_pri_reg_handler(ds_cb_arg_t arg, ds_ver_t *ver, ds_svc_hdl_t hdl)
705 {
706 	dev_info_t *dip = arg;
707 	ds_pri_state_t *sp;
708 	int instance;
709 
710 	instance = ddi_get_instance(dip);
711 	if ((sp = ddi_get_soft_state(ds_pri_statep, instance)) == NULL)
712 		return;
713 
714 	DS_PRI_DBG("ds_pri_reg_handler: registering handle 0x%lx for version "
715 	    "0x%x:0x%x\n", (uint64_t)hdl, ver->major, ver->minor);
716 
717 	/* When the domain service comes up automatically req the pri */
718 	mutex_enter(&sp->lock);
719 
720 	ASSERT(sp->ds_pri_handle == DS_INVALID_HDL);
721 	sp->ds_pri_handle = hdl;
722 
723 	ASSERT(sp->state == DS_PRI_NO_SERVICE);
724 	ASSERT(sp->ds_pri == NULL);
725 	ASSERT(sp->ds_pri_len == 0);
726 
727 	/* have service, but no PRI */
728 	sp->state |= DS_PRI_HAS_SERVICE;
729 
730 	/*
731 	 * Cannot request a PRI here, because the reg handler cannot
732 	 * do a DS send operation - we take care of this later.
733 	 */
734 
735 	/* Wake up anyone waiting in open() */
736 	cv_broadcast(&sp->cv);
737 
738 	mutex_exit(&sp->lock);
739 }
740 
741 
742 static void
743 ds_pri_unreg_handler(ds_cb_arg_t arg)
744 {
745 	dev_info_t *dip = arg;
746 	ds_pri_state_t *sp;
747 	int instance;
748 
749 	instance = ddi_get_instance(dip);
750 	if ((sp = ddi_get_soft_state(ds_pri_statep, instance)) == NULL)
751 		return;
752 
753 	DS_PRI_DBG("ds_pri_unreg_handler: un-registering ds_pri service\n");
754 
755 	mutex_enter(&sp->lock);
756 
757 	/* Once the service goes - if we have a PRI at hand free it up */
758 	if (sp->ds_pri_len != 0) {
759 		kmem_free(sp->ds_pri, sp->ds_pri_len);
760 		sp->ds_pri_len = 0;
761 		sp->ds_pri = NULL;
762 	}
763 	sp->ds_pri_handle = DS_INVALID_HDL;
764 	sp->state = DS_PRI_NO_SERVICE;
765 
766 	mutex_exit(&sp->lock);
767 }
768 
769 
770 static void
771 ds_pri_data_handler(ds_cb_arg_t arg, void *buf, size_t buflen)
772 {
773 	dev_info_t *dip = arg;
774 	ds_pri_state_t *sp;
775 	int instance;
776 	void *data;
777 	ds_pri_msg_t	*msgp;
778 	size_t	pri_size;
779 
780 	msgp = (ds_pri_msg_t *)buf;
781 
782 	/* make sure the header is at least valid */
783 	if (buflen < sizeof (msgp->hdr))
784 		return;
785 
786 	DS_PRI_DBG("ds_pri_data_handler: msg buf len 0x%lx : type 0x%lx, "
787 	    "seqn 0x%lx\n", buflen, msgp->hdr.type, msgp->hdr.seq_num);
788 
789 	instance = ddi_get_instance(dip);
790 	if ((sp = ddi_get_soft_state(ds_pri_statep, instance)) == NULL)
791 		return;
792 
793 	mutex_enter(&sp->lock);
794 
795 	ASSERT(sp->state & DS_PRI_HAS_SERVICE);
796 
797 	switch (msgp->hdr.type) {
798 	case DS_PRI_DATA:	/* in response to a request from us */
799 		break;
800 	case DS_PRI_UPDATE:	/* aynch notification */
801 			/* our default response to this is to request the PRI */
802 		/* simply issue a request for the new PRI */
803 		request_pri(sp);
804 		goto done;
805 	default:	/* ignore garbage or unknown message types */
806 		goto done;
807 	}
808 
809 	/*
810 	 * If there is no pending PRI request, then we've received a
811 	 * bogus data message ... so ignore it.
812 	 */
813 
814 	if (!(sp->state & DS_PRI_REQUESTED)) {
815 		cmn_err(CE_WARN, "Received DS pri data without request");
816 		goto done;
817 	}
818 
819 	/* response to a request therefore old PRI must be gone */
820 	ASSERT(!(sp->state & DS_PRI_HAS_PRI));
821 	ASSERT(sp->ds_pri_len == 0);
822 	ASSERT(sp->ds_pri == NULL);
823 
824 	/* response seq_num should match our request seq_num */
825 	if (msgp->hdr.seq_num != sp->last_req_id) {
826 		cmn_err(CE_WARN, "Received DS pri data out of sequence with "
827 		    "request");
828 		goto done;
829 	}
830 
831 	pri_size = buflen - sizeof (msgp->hdr);
832 	data = kmem_alloc(pri_size, KM_SLEEP);
833 	sp->ds_pri = data;
834 	sp->ds_pri_len = pri_size;
835 	bcopy(msgp->data, data, sp->ds_pri_len);
836 	sp->state &= ~DS_PRI_REQUESTED;
837 	sp->state |= DS_PRI_HAS_PRI;
838 
839 	sp->gencount++;
840 	cv_broadcast(&sp->cv);
841 
842 done:;
843 	mutex_exit(&sp->lock);
844 }
845