xref: /titanic_41/usr/src/lib/libds/common/libds.c (revision ba9236fbcb49a99c7d71c0c25d1e45cb2a75ac78)
130588217SMike Christensen /*
230588217SMike Christensen  * CDDL HEADER START
330588217SMike Christensen  *
430588217SMike Christensen  * The contents of this file are subject to the terms of the
530588217SMike Christensen  * Common Development and Distribution License (the "License").
630588217SMike Christensen  * You may not use this file except in compliance with the License.
730588217SMike Christensen  *
830588217SMike Christensen  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
930588217SMike Christensen  * or http://www.opensolaris.org/os/licensing.
1030588217SMike Christensen  * See the License for the specific language governing permissions
1130588217SMike Christensen  * and limitations under the License.
1230588217SMike Christensen  *
1330588217SMike Christensen  * When distributing Covered Code, include this CDDL HEADER in each
1430588217SMike Christensen  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
1530588217SMike Christensen  * If applicable, add the following below this CDDL HEADER, with the
1630588217SMike Christensen  * fields enclosed by brackets "[]" replaced with your own identifying
1730588217SMike Christensen  * information: Portions Copyright [yyyy] [name of copyright owner]
1830588217SMike Christensen  *
1930588217SMike Christensen  * CDDL HEADER END
2030588217SMike Christensen  */
2130588217SMike Christensen /*
2230588217SMike Christensen  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
2330588217SMike Christensen  * Use is subject to license terms.
2430588217SMike Christensen  */
2530588217SMike Christensen 
2630588217SMike Christensen #include <stdio.h>
2730588217SMike Christensen #include <fcntl.h>
2830588217SMike Christensen #include <unistd.h>
2930588217SMike Christensen #include <stdlib.h>
3030588217SMike Christensen #include <strings.h>
3130588217SMike Christensen #include <errno.h>
3230588217SMike Christensen #include <sys/types.h>
3330588217SMike Christensen #include <sys/sysevent.h>
3430588217SMike Christensen #include <libsysevent.h>
3530588217SMike Christensen #include <sys/vlds.h>
3630588217SMike Christensen #include "libds.h"
3730588217SMike Christensen 
3830588217SMike Christensen #define	PTRTOUINT64(ptr)	((uint64_t)((uintptr_t)(ptr)))
3930588217SMike Christensen static char vlds_device[] =
4030588217SMike Christensen 	"/devices/virtual-devices@100/channel-devices@200/"
4130588217SMike Christensen 	"virtual-domain-service@0:vlds";
4230588217SMike Christensen 
4330588217SMike Christensen typedef struct dslibentry {
4430588217SMike Christensen 	ds_hdl_t dsl_hdl;
4530588217SMike Christensen 	uint32_t dsl_flags;
46*ba9236fbSMike Christensen 	uint32_t dsl_tflags;
4730588217SMike Christensen 	char *dsl_service;
4830588217SMike Christensen 	ds_ops_t dsl_ops;
4930588217SMike Christensen } dslibentry_t;
5030588217SMike Christensen 
51*ba9236fbSMike Christensen /* dsl_tflags */
52*ba9236fbSMike Christensen #define	DSL_ENTRY_INUSE		0x0001	/* handle is currently active */
53*ba9236fbSMike Christensen 
5430588217SMike Christensen #define	MIN_DSLIB_ENTRIES	64
5530588217SMike Christensen static dslibentry_t *dslibtab;
5630588217SMike Christensen static int ndslib;
5730588217SMike Christensen 
5830588217SMike Christensen /*
5930588217SMike Christensen  * Lock to protect the dslibtab table.  We only need to protect this
6030588217SMike Christensen  * table for those functions which actually look at or modify the table:
6130588217SMike Christensen  * service registration (ds_svc_reg/ds_clnt_reg), service unregistration
6230588217SMike Christensen  * (ds_hdl_unreg) or during callbacks (ds_recv)
6330588217SMike Christensen  */
6430588217SMike Christensen static mutex_t dslib_lock;
6530588217SMike Christensen 
6630588217SMike Christensen static int ds_fd = -1;
6730588217SMike Christensen 
6830588217SMike Christensen static char *ds_sid_name = "vlds";
6930588217SMike Christensen 
7030588217SMike Christensen static evchan_t *ds_evchan;
7130588217SMike Christensen 
7230588217SMike Christensen /*
7330588217SMike Christensen  * Static functions internal to dslib.
7430588217SMike Christensen  */
7530588217SMike Christensen static dslibentry_t *ds_hdl_to_dslibentry(ds_hdl_t hdl);
76*ba9236fbSMike Christensen static dslibentry_t *ds_new_dslibentry(void);
77*ba9236fbSMike Christensen static uint_t ds_service_count(char *service, boolean_t is_client);
7830588217SMike Christensen static dslibentry_t *ds_lookup_dslibentry(char *service, boolean_t is_client);
7930588217SMike Christensen static dslibentry_t *ds_register_dslibentry(ds_hdl_t hdl, char *service,
8030588217SMike Christensen     boolean_t is_client);
8130588217SMike Christensen static void ds_free_dslibentry(dslibentry_t *dsp, int force_unreg);
8230588217SMike Christensen static int ds_recv(sysevent_t *sep, void *arg);
8330588217SMike Christensen static void ds_string_arg(vlds_string_t *dsp, char *str);
8430588217SMike Christensen static int ds_register(ds_capability_t *cap, ds_ops_t *ops, uint_t flags);
8530588217SMike Christensen 
8630588217SMike Christensen static dslibentry_t *
8730588217SMike Christensen ds_hdl_to_dslibentry(ds_hdl_t hdl)
8830588217SMike Christensen {
8930588217SMike Christensen 	int i;
9030588217SMike Christensen 	dslibentry_t *dsp;
9130588217SMike Christensen 
9230588217SMike Christensen 	for (i = 0, dsp = dslibtab; i < ndslib; i++, dsp++) {
9330588217SMike Christensen 		if (hdl == dsp->dsl_hdl)
9430588217SMike Christensen 			return (dsp);
9530588217SMike Christensen 	}
9630588217SMike Christensen 	return (NULL);
9730588217SMike Christensen }
9830588217SMike Christensen 
9930588217SMike Christensen static dslibentry_t *
10030588217SMike Christensen ds_new_dslibentry(void)
10130588217SMike Christensen {
10230588217SMike Christensen 	int newndslib;
10330588217SMike Christensen 	dslibentry_t *dsp;
10430588217SMike Christensen 
10530588217SMike Christensen 	if ((dsp = ds_hdl_to_dslibentry(NULL)) != NULL)
10630588217SMike Christensen 		return (dsp);
10730588217SMike Christensen 
10830588217SMike Christensen 	/* double the size */
10930588217SMike Christensen 	newndslib = ndslib << 1;
11030588217SMike Christensen 	if ((dslibtab = realloc(dslibtab, newndslib * sizeof (dslibentry_t)))
11130588217SMike Christensen 	    == NULL)
11230588217SMike Christensen 		return (NULL);
11330588217SMike Christensen 	dsp = &dslibtab[ndslib];
11430588217SMike Christensen 	(void) memset(dsp, 0, (newndslib - ndslib) * sizeof (dslibentry_t));
11530588217SMike Christensen 	ndslib = newndslib;
11630588217SMike Christensen 	return (dsp);
11730588217SMike Christensen }
11830588217SMike Christensen 
119*ba9236fbSMike Christensen static uint_t
120*ba9236fbSMike Christensen ds_service_count(char *service, boolean_t is_client)
121*ba9236fbSMike Christensen {
122*ba9236fbSMike Christensen 	int i;
123*ba9236fbSMike Christensen 	dslibentry_t *dsp;
124*ba9236fbSMike Christensen 	uint_t is_client_flag = is_client ? VLDS_REG_CLIENT : 0;
125*ba9236fbSMike Christensen 	uint_t count = 0;
126*ba9236fbSMike Christensen 
127*ba9236fbSMike Christensen 	for (i = 0, dsp = dslibtab; i < ndslib; i++, dsp++) {
128*ba9236fbSMike Christensen 		if (dsp->dsl_hdl != NULL &&
129*ba9236fbSMike Christensen 		    strcmp(dsp->dsl_service, service) == 0 &&
130*ba9236fbSMike Christensen 		    (dsp->dsl_flags & VLDS_REG_CLIENT) == is_client_flag) {
131*ba9236fbSMike Christensen 			count++;
132*ba9236fbSMike Christensen 		}
133*ba9236fbSMike Christensen 	}
134*ba9236fbSMike Christensen 	return (count);
135*ba9236fbSMike Christensen }
136*ba9236fbSMike Christensen 
13730588217SMike Christensen static dslibentry_t *
13830588217SMike Christensen ds_lookup_dslibentry(char *service, boolean_t is_client)
13930588217SMike Christensen {
14030588217SMike Christensen 	int i;
14130588217SMike Christensen 	dslibentry_t *dsp;
14230588217SMike Christensen 	uint_t is_client_flag = is_client ? VLDS_REG_CLIENT : 0;
14330588217SMike Christensen 
14430588217SMike Christensen 	for (i = 0, dsp = dslibtab; i < ndslib; i++, dsp++) {
14530588217SMike Christensen 		if (dsp->dsl_hdl != NULL &&
14630588217SMike Christensen 		    strcmp(dsp->dsl_service, service) == 0 &&
14730588217SMike Christensen 		    (dsp->dsl_flags & VLDS_REG_CLIENT) == is_client_flag) {
14830588217SMike Christensen 			return (dsp);
14930588217SMike Christensen 		}
15030588217SMike Christensen 	}
15130588217SMike Christensen 	return (NULL);
15230588217SMike Christensen }
15330588217SMike Christensen 
15430588217SMike Christensen static dslibentry_t *
15530588217SMike Christensen ds_register_dslibentry(ds_hdl_t hdl, char *service, boolean_t is_client)
15630588217SMike Christensen {
15730588217SMike Christensen 	dslibentry_t *dsp, *orig_dsp;
15830588217SMike Christensen 
159*ba9236fbSMike Christensen 	if ((dsp = ds_hdl_to_dslibentry(hdl)) != NULL) {
160*ba9236fbSMike Christensen 		dsp->dsl_tflags |= DSL_ENTRY_INUSE;
16130588217SMike Christensen 		return (dsp);
162*ba9236fbSMike Christensen 	}
16330588217SMike Christensen 
16430588217SMike Christensen 	if ((orig_dsp = ds_lookup_dslibentry(service, is_client)) == NULL) {
16530588217SMike Christensen 		return (NULL);
16630588217SMike Christensen 	}
16730588217SMike Christensen 
168*ba9236fbSMike Christensen 	if ((orig_dsp->dsl_tflags & DSL_ENTRY_INUSE) == 0) {
169*ba9236fbSMike Christensen 		/* use the original structure entry */
170*ba9236fbSMike Christensen 		orig_dsp->dsl_tflags |= DSL_ENTRY_INUSE;
171*ba9236fbSMike Christensen 		orig_dsp->dsl_hdl = hdl;
172*ba9236fbSMike Christensen 		return (orig_dsp);
173*ba9236fbSMike Christensen 	}
17430588217SMike Christensen 
17530588217SMike Christensen 	/* allocate a new structure entry */
17630588217SMike Christensen 	if ((dsp = ds_new_dslibentry()) == NULL)
17730588217SMike Christensen 		return (NULL);
178*ba9236fbSMike Christensen 
17930588217SMike Christensen 	*dsp = *orig_dsp;
18030588217SMike Christensen 	dsp->dsl_service = strdup(orig_dsp->dsl_service);
18130588217SMike Christensen 	dsp->dsl_hdl = hdl;
18230588217SMike Christensen 	return (dsp);
18330588217SMike Christensen }
18430588217SMike Christensen 
18530588217SMike Christensen /*
18630588217SMike Christensen  * Want to leave an entry in the dslib table even though all the
18730588217SMike Christensen  * handles may have been unregistered for it.
18830588217SMike Christensen  */
18930588217SMike Christensen static void
19030588217SMike Christensen ds_free_dslibentry(dslibentry_t *dsp, int force_unreg)
19130588217SMike Christensen {
19230588217SMike Christensen 	uint_t nhdls;
19330588217SMike Christensen 
19430588217SMike Christensen 	/*
195*ba9236fbSMike Christensen 	 * Find out if we have 1 or 2 or more handles for the given
196*ba9236fbSMike Christensen 	 * service.  Having one implies that we want to leave the entry
197*ba9236fbSMike Christensen 	 * intact but marked as not in use unless this is a ds_unreg_hdl
19830588217SMike Christensen 	 * (force_unreg is true).
19930588217SMike Christensen 	 */
200*ba9236fbSMike Christensen 	nhdls = ds_service_count(dsp->dsl_service,
201*ba9236fbSMike Christensen 	    (dsp->dsl_flags & VLDS_REG_CLIENT) != 0);
20230588217SMike Christensen 
203*ba9236fbSMike Christensen 	if ((nhdls == 1 && force_unreg) || nhdls >= 2) {
20430588217SMike Christensen 		dsp->dsl_hdl = NULL;
20530588217SMike Christensen 		if (dsp->dsl_service) {
20630588217SMike Christensen 			free(dsp->dsl_service);
20730588217SMike Christensen 		}
20830588217SMike Christensen 		(void) memset(dsp, 0, sizeof (dslibentry_t));
209*ba9236fbSMike Christensen 	} else if (nhdls == 1) {
210*ba9236fbSMike Christensen 		dsp->dsl_tflags &= ~DSL_ENTRY_INUSE;
21130588217SMike Christensen 	}
21230588217SMike Christensen }
21330588217SMike Christensen 
21430588217SMike Christensen /*ARGSUSED*/
21530588217SMike Christensen static int
21630588217SMike Christensen ds_recv(sysevent_t *sep, void *arg)
21730588217SMike Christensen {
21830588217SMike Christensen 	nvlist_t *nvl;
21930588217SMike Christensen 	uint64_t hdl;
22030588217SMike Christensen 	ds_ver_t ver;
22130588217SMike Christensen 	ds_domain_hdl_t dhdl;
22230588217SMike Christensen 	uchar_t *bufp;
22330588217SMike Christensen 	boolean_t is_client;
22430588217SMike Christensen 	uint_t buflen;
22530588217SMike Christensen 	char *subclass;
22630588217SMike Christensen 	char *servicep;
22730588217SMike Christensen 	dslibentry_t *dsp;
22830588217SMike Christensen 	ds_cb_arg_t cb_arg;
22930588217SMike Christensen 
23030588217SMike Christensen 	subclass = sysevent_get_subclass_name(sep);
23130588217SMike Christensen 	if (sysevent_get_attr_list(sep, &nvl) != 0) {
23230588217SMike Christensen 		return (0);
23330588217SMike Christensen 	}
23430588217SMike Christensen 
23530588217SMike Christensen 	if (nvlist_lookup_uint64(nvl, VLDS_HDL, &hdl) == 0) {
23630588217SMike Christensen 		if (strcmp(subclass, ESC_VLDS_REGISTER) == 0) {
23730588217SMike Christensen 			void (*reg_cb)(ds_hdl_t, ds_cb_arg_t, ds_ver_t *,
23830588217SMike Christensen 			    ds_domain_hdl_t) = NULL;
23930588217SMike Christensen 
24030588217SMike Christensen 			if (nvlist_lookup_string(nvl, VLDS_SERVICE_ID,
24130588217SMike Christensen 			    &servicep) == 0 &&
24230588217SMike Christensen 			    nvlist_lookup_boolean_value(nvl, VLDS_ISCLIENT,
24330588217SMike Christensen 			    &is_client) == 0) {
24430588217SMike Christensen 				(void) mutex_lock(&dslib_lock);
24530588217SMike Christensen 				if ((dsp = ds_register_dslibentry(hdl,
24630588217SMike Christensen 				    servicep, is_client)) != NULL) {
24730588217SMike Christensen 					reg_cb = dsp->dsl_ops.ds_reg_cb;
24830588217SMike Christensen 					cb_arg = dsp->dsl_ops.cb_arg;
24930588217SMike Christensen 				}
25030588217SMike Christensen 				(void) mutex_unlock(&dslib_lock);
25130588217SMike Christensen 				if (reg_cb != NULL &&
25230588217SMike Christensen 				    nvlist_lookup_uint64(nvl, VLDS_DOMAIN_HDL,
25330588217SMike Christensen 				    &dhdl) == 0 &&
25430588217SMike Christensen 				    nvlist_lookup_uint16(nvl, VLDS_VER_MAJOR,
25530588217SMike Christensen 				    &ver.major) == 0 &&
25630588217SMike Christensen 				    nvlist_lookup_uint16(nvl, VLDS_VER_MINOR,
25730588217SMike Christensen 				    &ver.minor) == 0) {
25830588217SMike Christensen 					(reg_cb)((ds_hdl_t)hdl, cb_arg, &ver,
25930588217SMike Christensen 					    dhdl);
26030588217SMike Christensen 				}
26130588217SMike Christensen 			}
26230588217SMike Christensen 		} else if (strcmp(subclass, ESC_VLDS_UNREGISTER) == 0) {
26330588217SMike Christensen 			void (*unreg_cb)(ds_hdl_t, ds_cb_arg_t) = NULL;
26430588217SMike Christensen 
26530588217SMike Christensen 			(void) mutex_lock(&dslib_lock);
26630588217SMike Christensen 			if ((dsp = ds_hdl_to_dslibentry(hdl)) != NULL) {
26730588217SMike Christensen 				unreg_cb = dsp->dsl_ops.ds_unreg_cb;
26830588217SMike Christensen 				cb_arg = dsp->dsl_ops.cb_arg;
26930588217SMike Christensen 				ds_free_dslibentry(dsp, 0);
27030588217SMike Christensen 			}
27130588217SMike Christensen 			(void) mutex_unlock(&dslib_lock);
27230588217SMike Christensen 			if (unreg_cb != NULL) {
27330588217SMike Christensen 				(unreg_cb)((ds_hdl_t)hdl, cb_arg);
27430588217SMike Christensen 			}
27530588217SMike Christensen 		} else if (strcmp(subclass, ESC_VLDS_DATA) == 0) {
27630588217SMike Christensen 			void (*data_cb)(ds_hdl_t, ds_cb_arg_t, void *,
27730588217SMike Christensen 			    size_t) = NULL;
27830588217SMike Christensen 
27930588217SMike Christensen 			(void) mutex_lock(&dslib_lock);
28030588217SMike Christensen 			if ((dsp = ds_hdl_to_dslibentry(hdl)) != NULL) {
28130588217SMike Christensen 				data_cb = dsp->dsl_ops.ds_data_cb;
28230588217SMike Christensen 				cb_arg = dsp->dsl_ops.cb_arg;
28330588217SMike Christensen 			}
28430588217SMike Christensen 			(void) mutex_unlock(&dslib_lock);
28530588217SMike Christensen 			if (data_cb != NULL &&
28630588217SMike Christensen 			    nvlist_lookup_byte_array(nvl, VLDS_DATA, &bufp,
28730588217SMike Christensen 			    &buflen) == 0) {
28830588217SMike Christensen 				(data_cb)((ds_hdl_t)hdl, cb_arg, bufp, buflen);
28930588217SMike Christensen 			}
29030588217SMike Christensen 		}
29130588217SMike Christensen 	}
29230588217SMike Christensen 	nvlist_free(nvl);
29330588217SMike Christensen 	return (0);
29430588217SMike Christensen }
29530588217SMike Christensen 
29630588217SMike Christensen static void
29730588217SMike Christensen ds_string_arg(vlds_string_t *dsp, char *str)
29830588217SMike Christensen {
29930588217SMike Christensen 	if (str == NULL) {
30030588217SMike Christensen 		dsp->vlds_strp = NULL;
30130588217SMike Christensen 		dsp->vlds_strlen = 0;
30230588217SMike Christensen 	} else {
30330588217SMike Christensen 		dsp->vlds_strp = PTRTOUINT64(str);
30430588217SMike Christensen 		dsp->vlds_strlen = strlen(str) + 1;
30530588217SMike Christensen 	}
30630588217SMike Christensen }
30730588217SMike Christensen 
30830588217SMike Christensen static int
30930588217SMike Christensen ds_init_sysev(void)
31030588217SMike Christensen {
31130588217SMike Christensen 	char evchan_name[MAX_CHNAME_LEN];
31230588217SMike Christensen 
31330588217SMike Christensen 	(void) sprintf(evchan_name, VLDS_SYSEV_CHAN_FMT, (int)getpid());
31430588217SMike Christensen 	if (sysevent_evc_bind(evchan_name, &ds_evchan, 0) != 0) {
31530588217SMike Christensen 		return (errno);
31630588217SMike Christensen 	}
31730588217SMike Christensen 	if (sysevent_evc_subscribe(ds_evchan, ds_sid_name, EC_VLDS,
31830588217SMike Christensen 	    ds_recv, NULL, 0) != 0) {
31930588217SMike Christensen 		sysevent_evc_unbind(ds_evchan);
32030588217SMike Christensen 		ds_evchan = NULL;
32130588217SMike Christensen 		return (errno);
32230588217SMike Christensen 	}
32330588217SMike Christensen 	return (0);
32430588217SMike Christensen }
32530588217SMike Christensen 
32630588217SMike Christensen int
32730588217SMike Christensen ds_init(void)
32830588217SMike Christensen {
32930588217SMike Christensen 	if (ds_fd >= 0)
33030588217SMike Christensen 		return (0);
33130588217SMike Christensen 
33230588217SMike Christensen 	if ((ds_fd = open(vlds_device, 0)) < 0)
33330588217SMike Christensen 		return (errno);
33430588217SMike Christensen 
33530588217SMike Christensen 	if (dslibtab == NULL) {
336*ba9236fbSMike Christensen 		dslibtab = malloc(sizeof (dslibentry_t) * MIN_DSLIB_ENTRIES);
337*ba9236fbSMike Christensen 		if (dslibtab == NULL)
33830588217SMike Christensen 			return (errno = ENOMEM);
33930588217SMike Christensen 		ndslib = MIN_DSLIB_ENTRIES;
34030588217SMike Christensen 		(void) memset(dslibtab, 0, sizeof (dslibentry_t) * ndslib);
34130588217SMike Christensen 	}
34230588217SMike Christensen 
34330588217SMike Christensen 	(void) mutex_init(&dslib_lock, USYNC_THREAD, NULL);
34430588217SMike Christensen 	return (0);
34530588217SMike Christensen }
34630588217SMike Christensen 
34730588217SMike Christensen static int
34830588217SMike Christensen ds_register(ds_capability_t *cap, ds_ops_t *ops, uint_t flags)
34930588217SMike Christensen {
35030588217SMike Christensen 	dslibentry_t *dsp;
35130588217SMike Christensen 	vlds_svc_reg_arg_t vlds_arg;
35230588217SMike Christensen 	vlds_cap_t vlds_cap;
35330588217SMike Christensen 	vlds_ver_t vlds_vers[VLDS_MAX_VERS];
35430588217SMike Christensen 	uint64_t hdl_arg;
35530588217SMike Christensen 	ds_hdl_t hdl;
35630588217SMike Christensen 	uint_t nhdls;
35730588217SMike Christensen 	int i;
35830588217SMike Christensen 
35930588217SMike Christensen 	if (cap == NULL || ops == NULL || cap->svc_id == NULL ||
36030588217SMike Christensen 	    cap->vers == NULL || (flags & (~VLDS_REG_CLIENT)) != 0) {
36130588217SMike Christensen 		return (errno = EINVAL);
36230588217SMike Christensen 	}
36330588217SMike Christensen 
36430588217SMike Christensen 	if (cap->nvers > VLDS_MAX_VERS) {
36530588217SMike Christensen 		return (errno = EINVAL);
36630588217SMike Christensen 	}
36730588217SMike Christensen 
36830588217SMike Christensen 	if (ds_fd < 0 && (errno = ds_init()) != 0) {
36930588217SMike Christensen 		return (errno);
37030588217SMike Christensen 	}
37130588217SMike Christensen 
37230588217SMike Christensen 	if (ds_hdl_lookup(cap->svc_id, (flags & VLDS_REG_CLIENT), NULL, 1,
37330588217SMike Christensen 	    &nhdls) == 0 && nhdls == 1) {
37430588217SMike Christensen 		return (errno = EALREADY);
37530588217SMike Christensen 	}
37630588217SMike Christensen 
37730588217SMike Christensen 	(void) mutex_lock(&dslib_lock);
37830588217SMike Christensen 	if ((dsp = ds_new_dslibentry()) == NULL) {
37930588217SMike Christensen 		(void) mutex_unlock(&dslib_lock);
38030588217SMike Christensen 		return (errno = ENOMEM);
38130588217SMike Christensen 	}
38230588217SMike Christensen 
38330588217SMike Christensen 	/* Setup device driver capability structure. */
38430588217SMike Christensen 
38530588217SMike Christensen 	/* service string */
38630588217SMike Christensen 	ds_string_arg(&vlds_cap.vlds_service, cap->svc_id);
38730588217SMike Christensen 
38830588217SMike Christensen 	/* version array */
38930588217SMike Christensen 	for (i = 0; i < cap->nvers; i++) {
39030588217SMike Christensen 		vlds_vers[i].vlds_major = cap->vers[i].major;
39130588217SMike Christensen 		vlds_vers[i].vlds_minor = cap->vers[i].minor;
39230588217SMike Christensen 	}
39330588217SMike Christensen 	vlds_cap.vlds_versp = PTRTOUINT64(vlds_vers);
39430588217SMike Christensen 	vlds_cap.vlds_nver = cap->nvers;
39530588217SMike Christensen 
39630588217SMike Christensen 	/*
39730588217SMike Christensen 	 * Format args for VLDS_SVC_REG ioctl.
39830588217SMike Christensen 	 */
39930588217SMike Christensen 
40030588217SMike Christensen 	vlds_arg.vlds_capp = PTRTOUINT64(&vlds_cap);
40130588217SMike Christensen 
40230588217SMike Christensen 	/* op flags */
40330588217SMike Christensen 	if (ops->ds_reg_cb != NULL)
40430588217SMike Christensen 		flags |= VLDS_REGCB_VALID;
40530588217SMike Christensen 	if (ops->ds_unreg_cb != NULL)
40630588217SMike Christensen 		flags |= VLDS_UNREGCB_VALID;
40730588217SMike Christensen 	if (ops->ds_data_cb != NULL)
40830588217SMike Christensen 		flags |= VLDS_DATACB_VALID;
40930588217SMike Christensen 	vlds_arg.vlds_reg_flags = flags;
41030588217SMike Christensen 
41130588217SMike Christensen 	/* returned handle */
41230588217SMike Christensen 	vlds_arg.vlds_hdlp = PTRTOUINT64(&hdl_arg);
41330588217SMike Christensen 
41430588217SMike Christensen 	if (ioctl(ds_fd, VLDS_SVC_REG, &vlds_arg) < 0) {
41530588217SMike Christensen 		(void) mutex_unlock(&dslib_lock);
41630588217SMike Christensen 		return (errno);
41730588217SMike Christensen 	}
41830588217SMike Christensen 
41930588217SMike Christensen 	/*
42030588217SMike Christensen 	 * Setup user callback sysevent channel.
42130588217SMike Christensen 	 */
42230588217SMike Christensen 	if ((flags & VLDS_ANYCB_VALID) != 0 && ds_evchan == NULL &&
42330588217SMike Christensen 	    ds_init_sysev() != 0) {
42430588217SMike Christensen 		(void) mutex_unlock(&dslib_lock);
42530588217SMike Christensen 		(void) ioctl(ds_fd, VLDS_UNREG_HDL, &vlds_arg);
42630588217SMike Christensen 		return (errno);
42730588217SMike Christensen 	}
42830588217SMike Christensen 
42930588217SMike Christensen 	hdl = hdl_arg;
43030588217SMike Christensen 
43130588217SMike Christensen 	/*
43230588217SMike Christensen 	 * Set entry values in dslibtab.
43330588217SMike Christensen 	 */
43430588217SMike Christensen 	dsp->dsl_hdl = hdl;
43530588217SMike Christensen 	dsp->dsl_flags = flags;
436*ba9236fbSMike Christensen 	dsp->dsl_tflags = 0;
43730588217SMike Christensen 	dsp->dsl_service = strdup(cap->svc_id);
43830588217SMike Christensen 	dsp->dsl_ops = *ops;
43930588217SMike Christensen 	(void) mutex_unlock(&dslib_lock);
44030588217SMike Christensen 	return (0);
44130588217SMike Christensen }
44230588217SMike Christensen 
44330588217SMike Christensen /*
44430588217SMike Christensen  * Registers a service provider.  Kicks off the handshake with other
44530588217SMike Christensen  * domain(s) to announce servce.  Callback events are as described above.
44630588217SMike Christensen  */
44730588217SMike Christensen int
44830588217SMike Christensen ds_svc_reg(ds_capability_t *cap, ds_ops_t *ops)
44930588217SMike Christensen {
45030588217SMike Christensen 	return (ds_register(cap, ops, 0));
45130588217SMike Christensen }
45230588217SMike Christensen 
45330588217SMike Christensen /*
45430588217SMike Christensen  * Registers interest in a service from a specific domain.  When that
45530588217SMike Christensen  * service is registered, the register callback is invoked.  When that
45630588217SMike Christensen  * service is unregistered, the unregister callback is invoked.  When
45730588217SMike Christensen  * data is received, the receive data callback is invoked.
45830588217SMike Christensen  */
45930588217SMike Christensen int
46030588217SMike Christensen ds_clnt_reg(ds_capability_t *cap, ds_ops_t *ops)
46130588217SMike Christensen {
46230588217SMike Christensen 	return (ds_register(cap, ops, VLDS_REG_CLIENT));
46330588217SMike Christensen }
46430588217SMike Christensen 
46530588217SMike Christensen /*
46630588217SMike Christensen  * Given a service name and type, returns the existing handle(s), if
46730588217SMike Christensen  * one or more exist.  This could be used to poll for the connection being
46830588217SMike Christensen  * registered or unregistered, rather than using the register/unregister
46930588217SMike Christensen  * callbacks.
47030588217SMike Christensen  */
47130588217SMike Christensen int
47230588217SMike Christensen ds_hdl_lookup(char *service, boolean_t is_client, ds_hdl_t *hdlsp,
47330588217SMike Christensen     uint_t maxhdls, uint_t *nhdlsp)
47430588217SMike Christensen {
47530588217SMike Christensen 	vlds_hdl_lookup_arg_t vlds_arg;
47630588217SMike Christensen 	uint64_t nhdls_arg;
47730588217SMike Christensen 
47830588217SMike Christensen 	errno = 0;
47930588217SMike Christensen 	if (ds_fd < 0) {
48030588217SMike Christensen 		return (errno = EBADF);
48130588217SMike Christensen 	}
48230588217SMike Christensen 
48330588217SMike Christensen 	if (service == NULL) {
48430588217SMike Christensen 		return (errno = EINVAL);
48530588217SMike Christensen 	}
48630588217SMike Christensen 
48730588217SMike Christensen 	ds_string_arg(&vlds_arg.vlds_service, service);
48830588217SMike Christensen 	vlds_arg.vlds_isclient = is_client ? VLDS_REG_CLIENT : 0;
48930588217SMike Christensen 	vlds_arg.vlds_hdlsp = PTRTOUINT64(hdlsp);
49030588217SMike Christensen 	vlds_arg.vlds_maxhdls = maxhdls;
49130588217SMike Christensen 	vlds_arg.vlds_nhdlsp = PTRTOUINT64(&nhdls_arg);
49230588217SMike Christensen 
49330588217SMike Christensen 	if (ioctl(ds_fd, VLDS_HDL_LOOKUP, &vlds_arg) < 0) {
49430588217SMike Christensen 		return (errno);
49530588217SMike Christensen 	}
49630588217SMike Christensen 
49730588217SMike Christensen 	*nhdlsp = nhdls_arg;
49830588217SMike Christensen 	return (0);
49930588217SMike Christensen }
50030588217SMike Christensen 
50130588217SMike Christensen /*
50230588217SMike Christensen  * Given a handle, return its associated domain.
50330588217SMike Christensen  */
50430588217SMike Christensen int
50530588217SMike Christensen ds_domain_lookup(ds_hdl_t hdl, ds_domain_hdl_t *dhdlp)
50630588217SMike Christensen {
50730588217SMike Christensen 	vlds_dmn_lookup_arg_t vlds_arg;
50830588217SMike Christensen 	uint64_t dhdl_arg;
50930588217SMike Christensen 
51030588217SMike Christensen 	if (ds_fd < 0) {
51130588217SMike Christensen 		return (errno = EBADF);
51230588217SMike Christensen 	}
51330588217SMike Christensen 
51430588217SMike Christensen 	vlds_arg.vlds_hdl = hdl;
51530588217SMike Christensen 	vlds_arg.vlds_dhdlp = PTRTOUINT64(&dhdl_arg);
51630588217SMike Christensen 
51730588217SMike Christensen 	if (ioctl(ds_fd, VLDS_DMN_LOOKUP, &vlds_arg) < 0) {
51830588217SMike Christensen 		return (errno);
51930588217SMike Christensen 	}
52030588217SMike Christensen 
52130588217SMike Christensen 	if (dhdlp) {
52230588217SMike Christensen 		*dhdlp = dhdl_arg;
52330588217SMike Christensen 	}
52430588217SMike Christensen 
52530588217SMike Christensen 	return (0);
52630588217SMike Christensen }
52730588217SMike Christensen 
52830588217SMike Christensen /*
52930588217SMike Christensen  * Unregisters either a service or an interest in that service
53030588217SMike Christensen  * indicated by the supplied handle.
53130588217SMike Christensen  */
53230588217SMike Christensen int
53330588217SMike Christensen ds_unreg_hdl(ds_hdl_t hdl)
53430588217SMike Christensen {
53530588217SMike Christensen 	dslibentry_t *dsp;
53630588217SMike Christensen 	vlds_unreg_hdl_arg_t vlds_arg;
53730588217SMike Christensen 
53830588217SMike Christensen 	(void) mutex_lock(&dslib_lock);
53930588217SMike Christensen 	if ((dsp = ds_hdl_to_dslibentry(hdl)) != NULL) {
54030588217SMike Christensen 		ds_free_dslibentry(dsp, 1);
54130588217SMike Christensen 	}
54230588217SMike Christensen 	(void) mutex_unlock(&dslib_lock);
54330588217SMike Christensen 
54430588217SMike Christensen 	if (ds_fd >= 0) {
54530588217SMike Christensen 		vlds_arg.vlds_hdl = hdl;
54630588217SMike Christensen 		(void) ioctl(ds_fd, VLDS_UNREG_HDL, &vlds_arg);
54730588217SMike Christensen 	}
54830588217SMike Christensen 
54930588217SMike Christensen 	return (0);
55030588217SMike Christensen }
55130588217SMike Christensen 
55230588217SMike Christensen /*
55330588217SMike Christensen  * Send data to the appropriate service provider or client
55430588217SMike Christensen  * indicated by the provided handle.  The sender will block
55530588217SMike Christensen  * until the message has been sent.  There is no guarantee
55630588217SMike Christensen  * that multiple calls to ds_send_msg by the same thread
55730588217SMike Christensen  * will result in the data showing up at the receiver in
55830588217SMike Christensen  * the same order as sent.  If multiple messages are required,
55930588217SMike Christensen  * it will be up to the sender and receiver to implement a
56030588217SMike Christensen  * protocol.
56130588217SMike Christensen  */
56230588217SMike Christensen int
56330588217SMike Christensen ds_send_msg(ds_hdl_t hdl, void *buf, size_t buflen)
56430588217SMike Christensen {
56530588217SMike Christensen 	vlds_send_msg_arg_t vlds_arg;
56630588217SMike Christensen 
56730588217SMike Christensen 	if (ds_fd < 0) {
56830588217SMike Christensen 		return (errno = EBADF);
56930588217SMike Christensen 	}
57030588217SMike Christensen 
57130588217SMike Christensen 	vlds_arg.vlds_hdl = hdl;
57230588217SMike Christensen 	vlds_arg.vlds_bufp = PTRTOUINT64(buf);
57330588217SMike Christensen 	vlds_arg.vlds_buflen = buflen;
57430588217SMike Christensen 
57530588217SMike Christensen 	if (ioctl(ds_fd, VLDS_SEND_MSG, &vlds_arg) < 0) {
57630588217SMike Christensen 		return (errno);
57730588217SMike Christensen 	}
57830588217SMike Christensen 
57930588217SMike Christensen 	return (0);
58030588217SMike Christensen }
58130588217SMike Christensen 
58230588217SMike Christensen /*
58330588217SMike Christensen  * Receive data from the appropriate service provider or client
58430588217SMike Christensen  * indicated by the provided handle.  The sender will block
58530588217SMike Christensen  * until a message has been received.
58630588217SMike Christensen  */
58730588217SMike Christensen int
58830588217SMike Christensen ds_recv_msg(ds_hdl_t hdl, void *buf, size_t buflen, size_t *msglen)
58930588217SMike Christensen {
59030588217SMike Christensen 	vlds_recv_msg_arg_t vlds_arg;
59130588217SMike Christensen 	uint64_t msglen_arg;
59230588217SMike Christensen 
59330588217SMike Christensen 	if (ds_fd < 0) {
59430588217SMike Christensen 		return (errno = EBADF);
59530588217SMike Christensen 	}
59630588217SMike Christensen 
59730588217SMike Christensen 	vlds_arg.vlds_hdl = hdl;
59830588217SMike Christensen 	vlds_arg.vlds_bufp = PTRTOUINT64(buf);
59930588217SMike Christensen 	vlds_arg.vlds_buflen = buflen;
60030588217SMike Christensen 	vlds_arg.vlds_msglenp = PTRTOUINT64(&msglen_arg);
60130588217SMike Christensen 
60230588217SMike Christensen 	if (ioctl(ds_fd, VLDS_RECV_MSG, &vlds_arg) < 0) {
60330588217SMike Christensen 		if (errno == EFBIG && msglen) {
60430588217SMike Christensen 			*msglen = msglen_arg;
60530588217SMike Christensen 		}
60630588217SMike Christensen 		return (errno);
60730588217SMike Christensen 	}
60830588217SMike Christensen 
60930588217SMike Christensen 	if (msglen) {
61030588217SMike Christensen 		*msglen = msglen_arg;
61130588217SMike Christensen 	}
61230588217SMike Christensen 
61330588217SMike Christensen 	return (0);
61430588217SMike Christensen }
61530588217SMike Christensen 
61630588217SMike Christensen int
61730588217SMike Christensen ds_isready(ds_hdl_t hdl, boolean_t *is_ready)
61830588217SMike Christensen {
61930588217SMike Christensen 	vlds_hdl_isready_arg_t vlds_arg;
62030588217SMike Christensen 	uint64_t is_ready_arg;
62130588217SMike Christensen 
62230588217SMike Christensen 	if (ds_fd < 0) {
62330588217SMike Christensen 		return (errno = EBADF);
62430588217SMike Christensen 	}
62530588217SMike Christensen 
62630588217SMike Christensen 	vlds_arg.vlds_hdl = hdl;
62730588217SMike Christensen 	vlds_arg.vlds_isreadyp = PTRTOUINT64(&is_ready_arg);
62830588217SMike Christensen 
62930588217SMike Christensen 	if (ioctl(ds_fd, VLDS_HDL_ISREADY, &vlds_arg) < 0) {
63030588217SMike Christensen 		return (errno);
63130588217SMike Christensen 	}
63230588217SMike Christensen 
63330588217SMike Christensen 	*is_ready = (is_ready_arg != 0);
63430588217SMike Christensen 	return (0);
63530588217SMike Christensen }
63630588217SMike Christensen 
63730588217SMike Christensen /*
63830588217SMike Christensen  * Given a domain name, return its associated domain handle.
63930588217SMike Christensen  */
64030588217SMike Christensen int
64130588217SMike Christensen ds_dom_name_to_hdl(char *domain_name, ds_domain_hdl_t *dhdlp)
64230588217SMike Christensen {
64330588217SMike Christensen 	vlds_dom_nam2hdl_arg_t vlds_arg;
64430588217SMike Christensen 	uint64_t dhdl_arg;
64530588217SMike Christensen 
64630588217SMike Christensen 	if (ds_fd < 0) {
64730588217SMike Christensen 		return (errno = EBADF);
64830588217SMike Christensen 	}
64930588217SMike Christensen 
65030588217SMike Christensen 	ds_string_arg(&vlds_arg.vlds_domain_name, domain_name);
65130588217SMike Christensen 	vlds_arg.vlds_dhdlp = PTRTOUINT64(&dhdl_arg);
65230588217SMike Christensen 
65330588217SMike Christensen 	if (ioctl(ds_fd, VLDS_DOM_NAM2HDL, &vlds_arg) < 0) {
65430588217SMike Christensen 		return (errno);
65530588217SMike Christensen 	}
65630588217SMike Christensen 
65730588217SMike Christensen 	if (dhdlp) {
65830588217SMike Christensen 		*dhdlp = dhdl_arg;
65930588217SMike Christensen 	}
66030588217SMike Christensen 
66130588217SMike Christensen 	return (0);
66230588217SMike Christensen }
66330588217SMike Christensen 
66430588217SMike Christensen /*
66530588217SMike Christensen  * Given a domain handle, return its associated domain name.
66630588217SMike Christensen  */
66730588217SMike Christensen int
66830588217SMike Christensen ds_dom_hdl_to_name(ds_domain_hdl_t dhdl, char *domain_name, uint_t maxnamlen)
66930588217SMike Christensen {
67030588217SMike Christensen 	vlds_dom_hdl2nam_arg_t vlds_arg;
67130588217SMike Christensen 
67230588217SMike Christensen 	if (ds_fd < 0) {
67330588217SMike Christensen 		return (errno = EBADF);
67430588217SMike Christensen 	}
67530588217SMike Christensen 
67630588217SMike Christensen 	vlds_arg.vlds_dhdl = dhdl;
67730588217SMike Christensen 	vlds_arg.vlds_domain_name.vlds_strp = PTRTOUINT64(domain_name);
67830588217SMike Christensen 	vlds_arg.vlds_domain_name.vlds_strlen = maxnamlen;
67930588217SMike Christensen 
68030588217SMike Christensen 	if (ioctl(ds_fd, VLDS_DOM_HDL2NAM, &vlds_arg) < 0) {
68130588217SMike Christensen 		return (errno);
68230588217SMike Christensen 	}
68330588217SMike Christensen 
68430588217SMike Christensen 	return (0);
68530588217SMike Christensen }
68630588217SMike Christensen 
68730588217SMike Christensen void
68830588217SMike Christensen ds_unreg_svc(char *service, boolean_t is_client)
68930588217SMike Christensen {
69030588217SMike Christensen 	ds_hdl_t hdl;
69130588217SMike Christensen 	uint_t nhdls;
69230588217SMike Christensen 
69330588217SMike Christensen 	while (ds_hdl_lookup(service, is_client, &hdl, 1, &nhdls) == 0 &&
69430588217SMike Christensen 	    nhdls == 1) {
69530588217SMike Christensen 		(void) ds_unreg_hdl(hdl);
69630588217SMike Christensen 	}
69730588217SMike Christensen }
69830588217SMike Christensen 
69930588217SMike Christensen void
70030588217SMike Christensen ds_fini(void)
70130588217SMike Christensen {
70230588217SMike Christensen 	int i;
70330588217SMike Christensen 	dslibentry_t *dsp;
70430588217SMike Christensen 
70530588217SMike Christensen 	if (ds_fd >= 0) {
70630588217SMike Christensen 		(void) close(ds_fd);
70730588217SMike Christensen 		ds_fd = -1;
70830588217SMike Christensen 	}
70930588217SMike Christensen 	if (ds_evchan) {
71030588217SMike Christensen 		(void) sysevent_evc_unsubscribe(ds_evchan, ds_sid_name);
71130588217SMike Christensen 		(void) sysevent_evc_unbind(ds_evchan);
71230588217SMike Christensen 		ds_evchan = NULL;
71330588217SMike Christensen 	}
71430588217SMike Christensen 	if (ndslib > 0) {
71530588217SMike Christensen 		(void) mutex_lock(&dslib_lock);
71630588217SMike Christensen 		for (i = 0, dsp = dslibtab; i < ndslib; i++, dsp++) {
71730588217SMike Christensen 			if (dsp->dsl_hdl == NULL)
71830588217SMike Christensen 				continue;
71930588217SMike Christensen 			if (dsp->dsl_service) {
72030588217SMike Christensen 				free(dsp->dsl_service);
72130588217SMike Christensen 			}
72230588217SMike Christensen 		}
72330588217SMike Christensen 		free(dslibtab);
72430588217SMike Christensen 		ndslib = 0;
72530588217SMike Christensen 		dslibtab = NULL;
72630588217SMike Christensen 		(void) mutex_unlock(&dslib_lock);
72730588217SMike Christensen 		(void) mutex_destroy(&dslib_lock);
72830588217SMike Christensen 	}
72930588217SMike Christensen }
730