ds_pri.c revision 4109:20d5b06dbce1
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
51static 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
64struct ds_pri_test_data {
65	size_t		size;
66	void		*data;
67};
68
69struct ds_pri_test_data32 {
70	size32_t	size;
71	caddr32_t	data;
72};
73#endif /* TEST_HARNESS */
74
75typedef	enum {
76	DS_PRI_REQUEST	= 0,
77	DS_PRI_DATA	= 1,
78	DS_PRI_UPDATE	= 2
79} ds_pri_msg_type_t;
80
81typedef	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 */
91typedef 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
98struct 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
116typedef struct ds_pri_state ds_pri_state_t;
117
118static void *ds_pri_statep;
119
120static void request_pri(ds_pri_state_t *sp);
121
122static int ds_pri_getinfo(dev_info_t *, ddi_info_cmd_t, void *, void **);
123static int ds_pri_attach(dev_info_t *, ddi_attach_cmd_t);
124static int ds_pri_detach(dev_info_t *, ddi_detach_cmd_t);
125static int ds_pri_open(dev_t *, int, int, cred_t *);
126static int ds_pri_close(dev_t, int, int, cred_t *);
127static int ds_pri_read(dev_t, struct uio *, cred_t *);
128static int ds_pri_ioctl(dev_t, int, intptr_t, int, cred_t *, int *);
129
130/*
131 * DS Callbacks
132 */
133static void ds_pri_reg_handler(ds_cb_arg_t, ds_ver_t *, ds_svc_hdl_t);
134static void ds_pri_unreg_handler(ds_cb_arg_t arg);
135static void ds_pri_data_handler(ds_cb_arg_t arg, void *buf, size_t buflen);
136
137/*
138 * PRI DS capability registration
139 */
140
141static ds_ver_t ds_pri_ver_1_0 = { 1, 0 };
142
143static 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 */
152static 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 */
162static 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
183static 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
197static struct modldrv modldrv = {
198	&mod_driverops,
199	"Domain Services PRI Driver 1.0",
200	&ds_pri_dev_ops
201};
202
203static struct modlinkage modlinkage = {
204	MODREV_1,
205	(void *)&modldrv,
206	NULL
207};
208
209
210int
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
230int
231_info(struct modinfo *modinfop)
232{
233	return (mod_info(&modlinkage, modinfop));
234}
235
236
237int
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*/
252static int
253ds_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
283static int
284ds_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
344fail:
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*/
355static int
356ds_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	ddi_remove_minor_node(dip, NULL);
385	cv_destroy(&sp->cv);
386	mutex_destroy(&sp->lock);
387	ddi_soft_state_free(ds_pri_statep, instance);
388
389	return (DDI_SUCCESS);
390}
391
392
393/*ARGSUSED*/
394static int
395ds_pri_open(dev_t *devp, int flag, int otyp, cred_t *credp)
396{
397	ds_pri_state_t *sp;
398	int instance;
399
400	if (otyp != OTYP_CHR)
401		return (EINVAL);
402
403	instance = getminor(*devp);
404	sp = ddi_get_soft_state(ds_pri_statep, instance);
405	if (sp == NULL)
406		return (ENXIO);
407
408	mutex_enter(&sp->lock);
409
410	/*
411	 * If we're here and the state is DS_PRI_NO_SERVICE then this
412	 * means that ds hasn't yet called the registration callback.
413	 * A while loop is necessary as we might have been woken up
414	 * prematurely, e.g., due to a debugger or "pstack" etc.
415	 * Wait here and the callback will signal us when it has completed
416	 * its work.
417	 */
418	while (sp->state == DS_PRI_NO_SERVICE) {
419		if (cv_wait_sig(&sp->cv, &sp->lock) == 0) {
420			mutex_exit(&sp->lock);
421			return (EINTR);
422		}
423	}
424
425	sp->num_opens++;
426	mutex_exit(&sp->lock);
427
428	/*
429	 * On open we dont fetch the PRI even if we have a valid service
430	 * handle. PRI fetch is essentially lazy and on-demand.
431	 */
432
433	DS_PRI_DBG("ds_pri_open: state = 0x%x\n", sp->state);
434
435	return (0);
436}
437
438
439/*ARGSUSED*/
440static int
441ds_pri_close(dev_t dev, int flag, int otyp, cred_t *credp)
442{
443	int instance;
444	ds_pri_state_t *sp;
445
446	if (otyp != OTYP_CHR)
447		return (EINVAL);
448
449	DS_PRI_DBG("ds_pri_close\n");
450
451	instance = getminor(dev);
452	if ((sp = ddi_get_soft_state(ds_pri_statep, instance)) == NULL)
453		return (ENXIO);
454
455	mutex_enter(&sp->lock);
456	if (!(sp->state & DS_PRI_HAS_SERVICE)) {
457		mutex_exit(&sp->lock);
458		return (0);
459	}
460
461	if (--sp->num_opens > 0) {
462		mutex_exit(&sp->lock);
463		return (0);
464	}
465
466	/* If we have an old PRI - remove it */
467	if (sp->state & DS_PRI_HAS_PRI) {
468		if (sp->ds_pri != NULL && sp->ds_pri_len > 0) {
469			/*
470			 * remove the old data if we have an
471			 * outstanding request
472			 */
473			kmem_free(sp->ds_pri, sp->ds_pri_len);
474			sp->ds_pri_len = 0;
475			sp->ds_pri = NULL;
476		}
477		sp->state &= ~DS_PRI_HAS_PRI;
478	}
479	sp->state &= ~DS_PRI_REQUESTED;
480	mutex_exit(&sp->lock);
481	return (0);
482}
483
484
485/*ARGSUSED*/
486static int
487ds_pri_read(dev_t dev, struct uio *uiop, cred_t *credp)
488{
489	ds_pri_state_t *sp;
490	int instance;
491	size_t len;
492	int retval;
493	caddr_t tmpbufp;
494
495	instance = getminor(dev);
496	if ((sp = ddi_get_soft_state(ds_pri_statep, instance)) == NULL)
497		return (ENXIO);
498
499	len = uiop->uio_resid;
500
501	if (len == 0)
502		return (0);
503
504	mutex_enter(&sp->lock);
505
506	DS_PRI_DBG("ds_pri_read: state = 0x%x\n", sp->state);
507
508	/* block or bail if there is no current PRI */
509	if (!(sp->state & DS_PRI_HAS_PRI)) {
510		DS_PRI_DBG("ds_pri_read: no PRI held\n");
511
512		if (uiop->uio_fmode & (FNDELAY | FNONBLOCK)) {
513			mutex_exit(&sp->lock);
514			return (EAGAIN);
515		}
516
517		while (!(sp->state & DS_PRI_HAS_PRI)) {
518			DS_PRI_DBG("ds_pri_read: state = 0x%x\n", sp->state);
519			request_pri(sp);
520			if (cv_wait_sig(&sp->cv, &sp->lock) == 0) {
521				mutex_exit(&sp->lock);
522				return (EINTR);
523			}
524		}
525	}
526
527	if (uiop->uio_offset < 0 || uiop->uio_offset > sp->ds_pri_len) {
528		mutex_exit(&sp->lock);
529		return (EINVAL);
530	}
531
532	if (len > (sp->ds_pri_len - uiop->uio_offset))
533		len = sp->ds_pri_len - uiop->uio_offset;
534
535	/* already checked that offset < ds_pri_len above */
536	if (len == 0) {
537		mutex_exit(&sp->lock);
538		return (0);
539	}
540
541	/*
542	 * We're supposed to move the data out to userland, but
543	 * that can suspend because of page faults etc., and meanwhile
544	 * other parts of this driver want to update the PRI buffer ...
545	 * we could hold the data buffer locked with a flag etc.,
546	 * but that's still a lock ... a simpler mechanism - if not quite
547	 * as performance efficient is to simply clone here the part of
548	 * the buffer we care about and then the original can be released
549	 * for further updates while the uiomove continues.
550	 */
551
552	tmpbufp = kmem_alloc(len, KM_SLEEP);
553	bcopy(((caddr_t)sp->ds_pri) + uiop->uio_offset, tmpbufp, len);
554	mutex_exit(&sp->lock);
555
556	retval = uiomove(tmpbufp, len, UIO_READ, uiop);
557
558	kmem_free(tmpbufp, len);
559
560	return (retval);
561}
562
563
564/*ARGSUSED*/
565static int
566ds_pri_ioctl(dev_t dev, int cmd, intptr_t arg, int mode, cred_t *credp,
567    int *rvalp)
568{
569	ds_pri_state_t *sp;
570	int instance;
571
572	instance = getminor(dev);
573	if ((sp = ddi_get_soft_state(ds_pri_statep, instance)) == NULL)
574		return (ENXIO);
575
576	switch (cmd) {
577	case DSPRI_GETINFO: {
578		struct dspri_info info;
579
580		if (!(mode & FREAD))
581			return (EACCES);
582
583		/*
584		 * We are not guaranteed that ddi_copyout(9F) will read
585		 * atomically anything larger than a byte.  Therefore we
586		 * must duplicate the size before copying it out to the user.
587		 */
588		mutex_enter(&sp->lock);
589
590loop:;
591		if (sp->state & DS_PRI_HAS_PRI) {
592			/* If we have a PRI simply return the info */
593			info.size = sp->ds_pri_len;
594			info.token = sp->gencount;
595		} else
596		if (!(sp->state & DS_PRI_HAS_SERVICE)) {
597			/* If we have no service return a nil response */
598			info.size = 0;
599			info.token = 0;
600		} else {
601			request_pri(sp);
602			/* wait for something & check again */
603			if (cv_wait_sig(&sp->cv, &sp->lock) == 0) {
604				mutex_exit(&sp->lock);
605				return (EINTR);
606			}
607			goto loop;
608		}
609		DS_PRI_DBG("ds_pri_ioctl: DSPRI_GETINFO sz=0x%lx tok=0x%lx\n",
610			info.size, info.token);
611		mutex_exit(&sp->lock);
612
613		if (ddi_copyout(&info, (void *)arg, sizeof (info), mode) != 0)
614			return (EFAULT);
615		break;
616	}
617
618	case DSPRI_WAIT: {
619		uint64_t gencount;
620
621		if (ddi_copyin((void *)arg, &gencount, sizeof (gencount),
622		    mode) != 0)
623			return (EFAULT);
624
625		mutex_enter(&sp->lock);
626
627		DS_PRI_DBG("ds_pri_ioctl: DSPRI_WAIT gen=0x%lx sp->gen=0x%lx\n",
628			gencount, sp->gencount);
629
630		while ((sp->state & DS_PRI_HAS_PRI) == 0 ||
631			gencount == sp->gencount) {
632			if ((sp->state & DS_PRI_HAS_PRI) == 0)
633				request_pri(sp);
634			if (cv_wait_sig(&sp->cv, &sp->lock) == 0) {
635				mutex_exit(&sp->lock);
636				return (EINTR);
637			}
638		}
639		mutex_exit(&sp->lock);
640		break;
641	}
642
643	default:
644		return (ENOTTY);
645	}
646	return (0);
647}
648
649
650	/* assumes sp->lock is held when called */
651static void
652request_pri(ds_pri_state_t *sp)
653{
654	ds_pri_msg_t reqmsg;
655
656	ASSERT(MUTEX_HELD(&sp->lock));
657
658	/* If a request is already pending we're done */
659	if (!(sp->state & DS_PRI_HAS_SERVICE))
660		return;
661	if (sp->state & DS_PRI_REQUESTED)
662		return;
663
664	/* If we have an old PRI - remove it */
665	if (sp->state & DS_PRI_HAS_PRI) {
666		ASSERT(sp->ds_pri_len != 0);
667		ASSERT(sp->ds_pri != NULL);
668
669		/* remove the old data if we have an outstanding request */
670		kmem_free(sp->ds_pri, sp->ds_pri_len);
671		sp->ds_pri_len = 0;
672		sp->ds_pri = NULL;
673		sp->state &= ~DS_PRI_HAS_PRI;
674	} else {
675		ASSERT(sp->ds_pri == NULL);
676		ASSERT(sp->ds_pri_len == 0);
677	}
678
679	reqmsg.hdr.seq_num = ++(sp->req_id);
680	reqmsg.hdr.type = DS_PRI_REQUEST;
681
682	DS_PRI_DBG("request_pri: request id 0x%lx\n", sp->req_id);
683
684		/*
685		 * Request consists of header only.
686		 * We don't care about fail status for ds_send;
687		 * if it does fail we will get an unregister callback
688		 * from the DS framework and we handle the state change
689		 * there.
690		 */
691	(void) ds_cap_send(sp->ds_pri_handle, &reqmsg, sizeof (reqmsg.hdr));
692
693	sp->state |= DS_PRI_REQUESTED;
694	sp->last_req_id = sp->req_id;
695}
696
697/*
698 * DS Callbacks
699 */
700/*ARGSUSED*/
701static void
702ds_pri_reg_handler(ds_cb_arg_t arg, ds_ver_t *ver, ds_svc_hdl_t hdl)
703{
704	dev_info_t *dip = arg;
705	ds_pri_state_t *sp;
706	int instance;
707
708	instance = ddi_get_instance(dip);
709	if ((sp = ddi_get_soft_state(ds_pri_statep, instance)) == NULL)
710		return;
711
712	DS_PRI_DBG("ds_pri_reg_handler: registering handle 0x%lx for version "
713		"0x%x:0x%x\n", (uint64_t)hdl, ver->major, ver->minor);
714
715	/* When the domain service comes up automatically req the pri */
716	mutex_enter(&sp->lock);
717
718	ASSERT(sp->ds_pri_handle == DS_INVALID_HDL);
719	sp->ds_pri_handle = hdl;
720
721	ASSERT(sp->state == DS_PRI_NO_SERVICE);
722	ASSERT(sp->ds_pri == NULL);
723	ASSERT(sp->ds_pri_len == 0);
724
725	/* have service, but no PRI */
726	sp->state |= DS_PRI_HAS_SERVICE;
727
728	/*
729	 * Cannot request a PRI here, because the reg handler cannot
730	 * do a DS send operation - we take care of this later.
731	 */
732
733	/* Wake up anyone waiting in open() */
734	cv_broadcast(&sp->cv);
735
736	mutex_exit(&sp->lock);
737}
738
739
740static void
741ds_pri_unreg_handler(ds_cb_arg_t arg)
742{
743	dev_info_t *dip = arg;
744	ds_pri_state_t *sp;
745	int instance;
746
747	instance = ddi_get_instance(dip);
748	if ((sp = ddi_get_soft_state(ds_pri_statep, instance)) == NULL)
749		return;
750
751	DS_PRI_DBG("ds_pri_unreg_handler: un-registering ds_pri service\n");
752
753	mutex_enter(&sp->lock);
754
755	/* Once the service goes - if we have a PRI at hand free it up */
756	if (sp->ds_pri_len != 0) {
757		kmem_free(sp->ds_pri, sp->ds_pri_len);
758		sp->ds_pri_len = 0;
759		sp->ds_pri = NULL;
760	}
761	sp->ds_pri_handle = DS_INVALID_HDL;
762	sp->state = DS_PRI_NO_SERVICE;
763
764	mutex_exit(&sp->lock);
765}
766
767
768static void
769ds_pri_data_handler(ds_cb_arg_t arg, void *buf, size_t buflen)
770{
771	dev_info_t *dip = arg;
772	ds_pri_state_t *sp;
773	int instance;
774	void *data;
775	ds_pri_msg_t	*msgp;
776	size_t	pri_size;
777
778	msgp = (ds_pri_msg_t *)buf;
779
780	/* make sure the header is at least valid */
781	if (buflen < sizeof (msgp->hdr))
782		return;
783
784	DS_PRI_DBG("ds_pri_data_handler: msg buf len 0x%lx : type 0x%lx, "
785		"seqn 0x%lx\n", buflen, msgp->hdr.type, msgp->hdr.seq_num);
786
787	instance = ddi_get_instance(dip);
788	if ((sp = ddi_get_soft_state(ds_pri_statep, instance)) == NULL)
789		return;
790
791	mutex_enter(&sp->lock);
792
793	ASSERT(sp->state & DS_PRI_HAS_SERVICE);
794
795	switch (msgp->hdr.type) {
796	case DS_PRI_DATA:	/* in response to a request from us */
797		break;
798	case DS_PRI_UPDATE:	/* aynch notification */
799			/* our default response to this is to request the PRI */
800		/* simply issue a request for the new PRI */
801		request_pri(sp);
802		goto done;
803	default:	/* ignore garbage or unknown message types */
804		goto done;
805	}
806
807	/*
808	 * If there is no pending PRI request, then we've received a
809	 * bogus data message ... so ignore it.
810	 */
811
812	if (!(sp->state & DS_PRI_REQUESTED)) {
813		cmn_err(CE_WARN, "Received DS pri data without request");
814		goto done;
815	}
816
817	/* response to a request therefore old PRI must be gone */
818	ASSERT(!(sp->state & DS_PRI_HAS_PRI));
819	ASSERT(sp->ds_pri_len == 0);
820	ASSERT(sp->ds_pri == NULL);
821
822	/* response seq_num should match our request seq_num */
823	if (msgp->hdr.seq_num != sp->last_req_id) {
824		cmn_err(CE_WARN, "Received DS pri data out of sequence with "
825			"request");
826		goto done;
827	}
828
829	pri_size = buflen - sizeof (msgp->hdr);
830	data = kmem_alloc(pri_size, KM_SLEEP);
831	sp->ds_pri = data;
832	sp->ds_pri_len = pri_size;
833	bcopy(msgp->data, data, sp->ds_pri_len);
834	sp->state &= ~DS_PRI_REQUESTED;
835	sp->state |= DS_PRI_HAS_PRI;
836
837	sp->gencount++;
838	cv_broadcast(&sp->cv);
839
840done:;
841	mutex_exit(&sp->lock);
842}
843