ds_pri.c revision 7656:2621e50fdf4a
1193323Sed/*
2193323Sed * CDDL HEADER START
3193323Sed *
4193323Sed * The contents of this file are subject to the terms of the
5193323Sed * Common Development and Distribution License (the "License").
6193323Sed * You may not use this file except in compliance with the License.
7193323Sed *
8193323Sed * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9193323Sed * or http://www.opensolaris.org/os/licensing.
10193323Sed * See the License for the specific language governing permissions
11193323Sed * and limitations under the License.
12193323Sed *
13193323Sed * When distributing Covered Code, include this CDDL HEADER in each
14202375Srdivacky * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15202375Srdivacky * If applicable, add the following below this CDDL HEADER, with the
16193323Sed * fields enclosed by brackets "[]" replaced with your own identifying
17193323Sed * information: Portions Copyright [yyyy] [name of copyright owner]
18193323Sed *
19202375Srdivacky * CDDL HEADER END
20202375Srdivacky */
21202375Srdivacky/*
22202375Srdivacky * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
23202375Srdivacky * Use is subject to license terms.
24202375Srdivacky */
25202375Srdivacky
26202375Srdivacky
27202375Srdivacky/*
28202375Srdivacky * sun4v domain services PRI driver
29202375Srdivacky */
30202375Srdivacky
31202375Srdivacky#include <sys/types.h>
32193323Sed#include <sys/file.h>
33193323Sed#include <sys/errno.h>
34193323Sed#include <sys/open.h>
35193323Sed#include <sys/cred.h>
36202375Srdivacky#include <sys/uio.h>
37202375Srdivacky#include <sys/stat.h>
38202375Srdivacky#include <sys/ksynch.h>
39202375Srdivacky#include <sys/modctl.h>
40193323Sed#include <sys/conf.h>
41202375Srdivacky#include <sys/devops.h>
42193323Sed#include <sys/debug.h>
43202375Srdivacky#include <sys/cmn_err.h>
44202375Srdivacky#include <sys/ddi.h>
45193323Sed#include <sys/sunddi.h>
46202878Srdivacky#include <sys/ds.h>
47193323Sed
48193323Sed#include <sys/ds_pri.h>
49193323Sed
50193323Sedstatic uint_t ds_pri_debug = 0;
51202375Srdivacky#define	DS_PRI_DBG	if (ds_pri_debug) printf
52202375Srdivacky
53202375Srdivacky#define	DS_PRI_NAME	"ds_pri"
54226633Sdim
55226633Sdim#define	TEST_HARNESS
56226633Sdim#ifdef TEST_HARNESS
57226633Sdim#define	DS_PRI_MAX_PRI_SIZE	(64 * 1024)
58193323Sed
59193323Sed#define	DSIOC_TEST_REG	97
60#define	DSIOC_TEST_UNREG	98
61#define	DSIOC_TEST_DATA	99
62
63struct ds_pri_test_data {
64	size_t		size;
65	void		*data;
66};
67
68struct ds_pri_test_data32 {
69	size32_t	size;
70	caddr32_t	data;
71};
72#endif /* TEST_HARNESS */
73
74typedef	enum {
75	DS_PRI_REQUEST	= 0,
76	DS_PRI_DATA	= 1,
77	DS_PRI_UPDATE	= 2
78} ds_pri_msg_type_t;
79
80typedef	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 */
90typedef 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
97struct 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
115typedef struct ds_pri_state ds_pri_state_t;
116
117static void *ds_pri_statep;
118
119static void request_pri(ds_pri_state_t *sp);
120
121static int ds_pri_getinfo(dev_info_t *, ddi_info_cmd_t, void *, void **);
122static int ds_pri_attach(dev_info_t *, ddi_attach_cmd_t);
123static int ds_pri_detach(dev_info_t *, ddi_detach_cmd_t);
124static int ds_pri_open(dev_t *, int, int, cred_t *);
125static int ds_pri_close(dev_t, int, int, cred_t *);
126static int ds_pri_read(dev_t, struct uio *, cred_t *);
127static int ds_pri_ioctl(dev_t, int, intptr_t, int, cred_t *, int *);
128
129/*
130 * DS Callbacks
131 */
132static void ds_pri_reg_handler(ds_cb_arg_t, ds_ver_t *, ds_svc_hdl_t);
133static void ds_pri_unreg_handler(ds_cb_arg_t arg);
134static void ds_pri_data_handler(ds_cb_arg_t arg, void *buf, size_t buflen);
135
136/*
137 * PRI DS capability registration
138 */
139
140static ds_ver_t ds_pri_ver_1_0 = { 1, 0 };
141
142static 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 */
151static 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 */
161static 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
182static 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
197static struct modldrv modldrv = {
198	&mod_driverops,
199	"Domain Services PRI Driver",
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	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*/
396static int
397ds_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*/
442static int
443ds_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*/
488static int
489ds_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*/
567static int
568ds_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
592loop:;
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 */
653static void
654request_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*/
703static void
704ds_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
742static void
743ds_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
770static void
771ds_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
842done:;
843	mutex_exit(&sp->lock);
844}
845