xref: /illumos-gate/usr/src/uts/sun4v/io/ds_drv.c (revision 94e47c8d)
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 /*
2340c61268SMike Christensen  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
2430588217SMike Christensen  * Use is subject to license terms.
2530588217SMike Christensen  */
2630588217SMike Christensen 
2730588217SMike Christensen 
2830588217SMike Christensen /*
2930588217SMike Christensen  * Domain Services Module System Specific Code.
3030588217SMike Christensen  *
3130588217SMike Christensen  * The Domain Services (DS) module is responsible for communication
3230588217SMike Christensen  * with external service entities. It provides a kernel API for clients to
3330588217SMike Christensen  * publish capabilities and handles the low level communication and
3430588217SMike Christensen  * version negotiation required to export those capabilities to any
3530588217SMike Christensen  * interested service entity. Once a capability has been successfully
3630588217SMike Christensen  * registered with a service entity, the DS module facilitates all
3730588217SMike Christensen  * data transfers between the service entity and the client providing
3830588217SMike Christensen  * that particular capability.
3930588217SMike Christensen  *
4030588217SMike Christensen  * This file provides the system interfaces that are required for
4130588217SMike Christensen  * the ds.c module, which is common to both Solaris and VBSC (linux).
4230588217SMike Christensen  */
4330588217SMike Christensen 
4430588217SMike Christensen #include <sys/modctl.h>
4530588217SMike Christensen #include <sys/ksynch.h>
4630588217SMike Christensen #include <sys/taskq.h>
4730588217SMike Christensen #include <sys/disp.h>
4830588217SMike Christensen #include <sys/cmn_err.h>
4930588217SMike Christensen #include <sys/note.h>
5030588217SMike Christensen #include <sys/mach_descrip.h>
5130588217SMike Christensen #include <sys/mdesc.h>
5230588217SMike Christensen #include <sys/mdeg.h>
5330588217SMike Christensen #include <sys/ldc.h>
5430588217SMike Christensen #include <sys/ds.h>
5530588217SMike Christensen #include <sys/ds_impl.h>
5630588217SMike Christensen 
5730588217SMike Christensen /*
5830588217SMike Christensen  * Taskq for internal task processing
5930588217SMike Christensen  */
6030588217SMike Christensen static taskq_t *ds_taskq;
6130588217SMike Christensen 
6230588217SMike Christensen /*
6330588217SMike Christensen  * The actual required number of parallel threads is not expected
6430588217SMike Christensen  * to be very large. Use the maximum number of CPUs in the system
6530588217SMike Christensen  * as a rough upper bound.
6630588217SMike Christensen  */
6730588217SMike Christensen #define	DS_MAX_TASKQ_THR	NCPU
6830588217SMike Christensen #define	DS_DISPATCH(fn, arg)	taskq_dispatch(ds_taskq, fn, arg, TQ_SLEEP)
6930588217SMike Christensen 
70a600f50dSMike Christensen ds_domain_hdl_t ds_my_domain_hdl = DS_DHDL_INVALID;
71a600f50dSMike Christensen char *ds_my_domain_name = NULL;
7230588217SMike Christensen 
7330588217SMike Christensen #ifdef DEBUG
7430588217SMike Christensen /*
7530588217SMike Christensen  * Debug Flag
7630588217SMike Christensen  */
7730588217SMike Christensen uint_t ds_debug = 0;
7830588217SMike Christensen #endif	/* DEBUG */
7930588217SMike Christensen 
8030588217SMike Christensen /* initialization functions */
8130588217SMike Christensen static void ds_init(void);
8230588217SMike Christensen static void ds_fini(void);
8330588217SMike Christensen static int ds_ports_init(void);
8430588217SMike Christensen static int ds_ports_fini(void);
8530588217SMike Christensen 
8630588217SMike Christensen /* port utilities */
8730588217SMike Christensen static int ds_port_add(md_t *mdp, mde_cookie_t port, mde_cookie_t chan);
8830588217SMike Christensen 
8930588217SMike Christensen /* log functions */
9030588217SMike Christensen static void ds_log_init(void);
9130588217SMike Christensen static void ds_log_fini(void);
9230588217SMike Christensen static int ds_log_remove(void);
9330588217SMike Christensen static void ds_log_purge(void *arg);
9430588217SMike Christensen 
9530588217SMike Christensen static struct modlmisc modlmisc = {
9630588217SMike Christensen 	&mod_miscops,
9730588217SMike Christensen 	"Domain Services 1.9"
9830588217SMike Christensen };
9930588217SMike Christensen 
10030588217SMike Christensen static struct modlinkage modlinkage = {
10130588217SMike Christensen 	MODREV_1,
10230588217SMike Christensen 	(void *)&modlmisc,
10330588217SMike Christensen 	NULL
10430588217SMike Christensen };
10530588217SMike Christensen 
10630588217SMike Christensen int
_init(void)10730588217SMike Christensen _init(void)
10830588217SMike Christensen {
10930588217SMike Christensen 	int	rv;
11030588217SMike Christensen 
11130588217SMike Christensen 	/*
11230588217SMike Christensen 	 * Perform all internal setup before initializing
11330588217SMike Christensen 	 * the DS ports. This ensures that events can be
11430588217SMike Christensen 	 * processed as soon as the port comes up.
11530588217SMike Christensen 	 */
11630588217SMike Christensen 	ds_init();
11730588217SMike Christensen 
11830588217SMike Christensen 	/* force attach channel nexus */
11930588217SMike Christensen 	(void) i_ddi_attach_hw_nodes("cnex");
12030588217SMike Christensen 
12130588217SMike Christensen 	if ((rv = ds_ports_init()) != 0) {
12230588217SMike Christensen 		cmn_err(CE_WARN, "Domain Services initialization failed");
12330588217SMike Christensen 		ds_fini();
12430588217SMike Christensen 		return (rv);
12530588217SMike Christensen 	}
12630588217SMike Christensen 
12730588217SMike Christensen 	if ((rv = mod_install(&modlinkage)) != 0) {
12830588217SMike Christensen 		(void) ds_ports_fini();
12930588217SMike Christensen 		ds_fini();
13030588217SMike Christensen 	}
13130588217SMike Christensen 
13230588217SMike Christensen 	return (rv);
13330588217SMike Christensen }
13430588217SMike Christensen 
13530588217SMike Christensen int
_info(struct modinfo * modinfop)13630588217SMike Christensen _info(struct modinfo *modinfop)
13730588217SMike Christensen {
13830588217SMike Christensen 	return (mod_info(&modlinkage, modinfop));
13930588217SMike Christensen }
14030588217SMike Christensen 
14130588217SMike Christensen int
_fini(void)14230588217SMike Christensen _fini(void)
14330588217SMike Christensen {
14430588217SMike Christensen 	int	rv;
14530588217SMike Christensen 
14630588217SMike Christensen 	if ((rv = mod_remove(&modlinkage)) == 0) {
14730588217SMike Christensen 		(void) ds_ports_fini();
14830588217SMike Christensen 		ds_fini();
14930588217SMike Christensen 	}
15030588217SMike Christensen 
15130588217SMike Christensen 	return (rv);
15230588217SMike Christensen }
15330588217SMike Christensen 
15430588217SMike Christensen static void
ds_fini(void)15530588217SMike Christensen ds_fini(void)
15630588217SMike Christensen {
15730588217SMike Christensen 	/*
15830588217SMike Christensen 	 * Flip the enabled switch to make sure that no
15930588217SMike Christensen 	 * incoming events get dispatched while things
16030588217SMike Christensen 	 * are being torn down.
16130588217SMike Christensen 	 */
16230588217SMike Christensen 	ds_enabled = B_FALSE;
16330588217SMike Christensen 
16430588217SMike Christensen 	/*
16530588217SMike Christensen 	 * Destroy the taskq.
16630588217SMike Christensen 	 */
16730588217SMike Christensen 	taskq_destroy(ds_taskq);
16830588217SMike Christensen 
16930588217SMike Christensen 	/*
17030588217SMike Christensen 	 * Destroy the message log.
17130588217SMike Christensen 	 */
17230588217SMike Christensen 	ds_log_fini();
17330588217SMike Christensen 
17430588217SMike Christensen 	/*
17530588217SMike Christensen 	 * Deallocate the table of registered services
17630588217SMike Christensen 	 */
17730588217SMike Christensen 
17830588217SMike Christensen 	/* clear out all entries */
17930588217SMike Christensen 	mutex_enter(&ds_svcs.lock);
18030588217SMike Christensen 	(void) ds_walk_svcs(ds_svc_free, NULL);
18130588217SMike Christensen 	mutex_exit(&ds_svcs.lock);
18230588217SMike Christensen 
18330588217SMike Christensen 	/* destroy the table itself */
18430588217SMike Christensen 	DS_FREE(ds_svcs.tbl, ds_svcs.maxsvcs * sizeof (ds_svc_t *));
18530588217SMike Christensen 	mutex_destroy(&ds_svcs.lock);
18630588217SMike Christensen 	bzero(&ds_svcs, sizeof (ds_svcs));
18730588217SMike Christensen }
18830588217SMike Christensen 
18930588217SMike Christensen /*
19030588217SMike Christensen  * Initialize the list of ports based on the MD.
19130588217SMike Christensen  */
19230588217SMike Christensen static int
ds_ports_init(void)19330588217SMike Christensen ds_ports_init(void)
19430588217SMike Christensen {
19530588217SMike Christensen 	int		idx;
19630588217SMike Christensen 	int		rv = 0;
19730588217SMike Christensen 	md_t		*mdp;
19830588217SMike Christensen 	int		num_nodes;
19930588217SMike Christensen 	int		listsz;
20030588217SMike Christensen 	mde_cookie_t	rootnode;
20130588217SMike Christensen 	mde_cookie_t	dsnode;
20230588217SMike Christensen 	mde_cookie_t	*portp = NULL;
20330588217SMike Christensen 	mde_cookie_t	*chanp = NULL;
20430588217SMike Christensen 	int		nport;
20530588217SMike Christensen 	int		nchan;
20630588217SMike Christensen 
20730588217SMike Christensen 	if ((mdp = md_get_handle()) == NULL) {
20830588217SMike Christensen 		cmn_err(CE_WARN, "Unable to initialize machine description");
20930588217SMike Christensen 		return (-1);
21030588217SMike Christensen 	}
21130588217SMike Christensen 
21230588217SMike Christensen 	num_nodes = md_node_count(mdp);
21330588217SMike Christensen 	ASSERT(num_nodes > 0);
21430588217SMike Christensen 
21530588217SMike Christensen 	listsz = num_nodes * sizeof (mde_cookie_t);
21630588217SMike Christensen 
21730588217SMike Christensen 	/* allocate temporary storage for MD scans */
21830588217SMike Christensen 	portp = kmem_zalloc(listsz, KM_SLEEP);
21930588217SMike Christensen 	chanp = kmem_zalloc(listsz, KM_SLEEP);
22030588217SMike Christensen 
22130588217SMike Christensen 	rootnode = md_root_node(mdp);
22230588217SMike Christensen 	ASSERT(rootnode != MDE_INVAL_ELEM_COOKIE);
22330588217SMike Christensen 
22430588217SMike Christensen 	/*
22530588217SMike Christensen 	 * The root of the search for DS port nodes is the
22630588217SMike Christensen 	 * DS node. Perform a scan to find that node.
22730588217SMike Christensen 	 */
22830588217SMike Christensen 	nport = md_scan_dag(mdp, rootnode, md_find_name(mdp, DS_MD_ROOT_NAME),
22930588217SMike Christensen 	    md_find_name(mdp, "fwd"), portp);
23030588217SMike Christensen 
23130588217SMike Christensen 	if (nport <= 0) {
23230588217SMike Christensen 		DS_DBG_MD(CE_NOTE, "No '%s' node in MD", DS_MD_ROOT_NAME);
23330588217SMike Christensen 		goto done;
23430588217SMike Christensen 	}
23530588217SMike Christensen 
23630588217SMike Christensen 	/* expecting only one DS node */
23730588217SMike Christensen 	if (nport != 1) {
23830588217SMike Christensen 		DS_DBG_MD(CE_NOTE, "Expected one '%s' node in the MD, found %d",
23930588217SMike Christensen 		    DS_MD_ROOT_NAME, nport);
24030588217SMike Christensen 	}
24130588217SMike Christensen 
24230588217SMike Christensen 	dsnode = portp[0];
24330588217SMike Christensen 
24430588217SMike Christensen 	/* find all the DS ports in the MD */
24530588217SMike Christensen 	nport = md_scan_dag(mdp, dsnode, md_find_name(mdp, DS_MD_PORT_NAME),
24630588217SMike Christensen 	    md_find_name(mdp, "fwd"), portp);
24730588217SMike Christensen 
24830588217SMike Christensen 	if (nport <= 0) {
24930588217SMike Christensen 		DS_DBG_MD(CE_NOTE, "No '%s' nodes in MD", DS_MD_PORT_NAME);
25030588217SMike Christensen 		goto done;
25130588217SMike Christensen 	}
25230588217SMike Christensen 
25330588217SMike Christensen 	/*
25430588217SMike Christensen 	 * Initialize all the ports found in the MD.
25530588217SMike Christensen 	 */
25630588217SMike Christensen 	for (idx = 0; idx < nport; idx++) {
25730588217SMike Christensen 
25830588217SMike Christensen 		/* get the channels for this port */
25930588217SMike Christensen 		nchan = md_scan_dag(mdp, portp[idx],
26030588217SMike Christensen 		    md_find_name(mdp, DS_MD_CHAN_NAME),
26130588217SMike Christensen 		    md_find_name(mdp, "fwd"), chanp);
26230588217SMike Christensen 
26330588217SMike Christensen 		if (nchan <= 0) {
26430588217SMike Christensen 			cmn_err(CE_WARN, "No '%s' node for DS port",
26530588217SMike Christensen 			    DS_MD_CHAN_NAME);
26630588217SMike Christensen 			rv = -1;
26730588217SMike Christensen 			goto done;
26830588217SMike Christensen 		}
26930588217SMike Christensen 
27030588217SMike Christensen 		/* expecting only one channel */
27130588217SMike Christensen 		if (nchan != 1) {
27230588217SMike Christensen 			DS_DBG_MD(CE_NOTE, "Expected one '%s' node for DS "
27330588217SMike Christensen 			    " port,  found %d", DS_MD_CHAN_NAME, nchan);
27430588217SMike Christensen 		}
27530588217SMike Christensen 
27630588217SMike Christensen 		if (ds_port_add(mdp, portp[idx], chanp[0]) != 0) {
27730588217SMike Christensen 			rv = -1;
27830588217SMike Christensen 			goto done;
27930588217SMike Christensen 		}
28030588217SMike Christensen 	}
28130588217SMike Christensen 
28230588217SMike Christensen done:
28330588217SMike Christensen 	if (rv != 0)
28430588217SMike Christensen 		(void) ds_ports_fini();
28530588217SMike Christensen 
28630588217SMike Christensen 	DS_FREE(portp, listsz);
28730588217SMike Christensen 	DS_FREE(chanp, listsz);
28830588217SMike Christensen 
28930588217SMike Christensen 	(void) md_fini_handle(mdp);
29030588217SMike Christensen 
29130588217SMike Christensen 	return (rv);
29230588217SMike Christensen }
29330588217SMike Christensen 
29430588217SMike Christensen static int
ds_ports_fini(void)29530588217SMike Christensen ds_ports_fini(void)
29630588217SMike Christensen {
29730588217SMike Christensen 	int		idx;
29830588217SMike Christensen 
29930588217SMike Christensen 	/*
30030588217SMike Christensen 	 * Tear down each initialized port.
30130588217SMike Christensen 	 */
30230588217SMike Christensen 	for (idx = 0; idx < DS_MAX_PORTS; idx++) {
30330588217SMike Christensen 		if (DS_PORT_IN_SET(ds_allports, idx)) {
30430588217SMike Christensen 			(void) ds_remove_port(idx, 1);
30530588217SMike Christensen 		}
30630588217SMike Christensen 	}
30730588217SMike Christensen 
30830588217SMike Christensen 	return (0);
30930588217SMike Christensen }
31030588217SMike Christensen 
31130588217SMike Christensen static int
ds_port_add(md_t * mdp,mde_cookie_t port,mde_cookie_t chan)31230588217SMike Christensen ds_port_add(md_t *mdp, mde_cookie_t port, mde_cookie_t chan)
31330588217SMike Christensen {
31430588217SMike Christensen 	uint64_t	port_id;
31530588217SMike Christensen 	uint64_t	ldc_id;
31640c61268SMike Christensen 	uint8_t		*ldcidsp;
31740c61268SMike Christensen 	int		len;
31830588217SMike Christensen 
31930588217SMike Christensen 	/* get the ID for this port */
32030588217SMike Christensen 	if (md_get_prop_val(mdp, port, "id", &port_id) != 0) {
32130588217SMike Christensen 		cmn_err(CE_WARN, "%s: port 'id' property not found",
32230588217SMike Christensen 		    __func__);
32330588217SMike Christensen 		return (-1);
32430588217SMike Christensen 	}
32530588217SMike Christensen 
32630588217SMike Christensen 	/* sanity check the port id */
32730588217SMike Christensen 	if (port_id > DS_MAX_PORT_ID) {
32830588217SMike Christensen 		cmn_err(CE_WARN, "%s: port ID %ld out of range",
32930588217SMike Christensen 		    __func__, port_id);
33030588217SMike Christensen 		return (-1);
33130588217SMike Christensen 	}
33230588217SMike Christensen 
33330588217SMike Christensen 	/* get the channel ID for this port */
33430588217SMike Christensen 	if (md_get_prop_val(mdp, chan, "id", &ldc_id) != 0) {
33530588217SMike Christensen 		cmn_err(CE_WARN, "ds@%lx: %s: no channel 'id' property",
33630588217SMike Christensen 		    port_id, __func__);
33730588217SMike Christensen 		return (-1);
33830588217SMike Christensen 	}
33930588217SMike Christensen 
340a600f50dSMike Christensen 	if (ds_add_port(port_id, ldc_id, DS_DHDL_INVALID, NULL, 1) != 0)
34130588217SMike Christensen 		return (-1);
34230588217SMike Christensen 
34340c61268SMike Christensen 	/*
34440c61268SMike Christensen 	 * Identify the SP Port.  The SP port is the only one with
34540c61268SMike Christensen 	 * the "ldc-ids" property, and is only on the primary domain.
34640c61268SMike Christensen 	 */
34740c61268SMike Christensen 	if (ds_sp_port_id == DS_PORTID_INVALID &&
34840c61268SMike Christensen 	    md_get_prop_data(mdp, port, "ldc-ids", &ldcidsp, &len) == 0) {
34940c61268SMike Christensen 		ds_sp_port_id = port_id;
35040c61268SMike Christensen 	}
35140c61268SMike Christensen 
35230588217SMike Christensen 	return (0);
35330588217SMike Christensen }
35430588217SMike Christensen 
355a600f50dSMike Christensen void
ds_set_my_dom_hdl_name(ds_domain_hdl_t dhdl,char * name)356a600f50dSMike Christensen ds_set_my_dom_hdl_name(ds_domain_hdl_t dhdl, char *name)
357a600f50dSMike Christensen {
358a600f50dSMike Christensen 	ds_my_domain_hdl = dhdl;
359a600f50dSMike Christensen 	if (ds_my_domain_name != NULL) {
360a600f50dSMike Christensen 		DS_FREE(ds_my_domain_name, strlen(ds_my_domain_name)+1);
361a600f50dSMike Christensen 		ds_my_domain_name = NULL;
362a600f50dSMike Christensen 	}
363a600f50dSMike Christensen 	if (name != NULL) {
364a600f50dSMike Christensen 		ds_my_domain_name = ds_strdup(name);
365a600f50dSMike Christensen 	}
366a600f50dSMike Christensen }
367a600f50dSMike Christensen 
36830588217SMike Christensen void
ds_init()36930588217SMike Christensen ds_init()
37030588217SMike Christensen {
37130588217SMike Christensen 	ds_common_init();
37230588217SMike Christensen 
37330588217SMike Christensen 	/*
37430588217SMike Christensen 	 * Create taskq for internal processing threads. This
37530588217SMike Christensen 	 * includes processing incoming request messages and
37630588217SMike Christensen 	 * sending out of band registration messages.
37730588217SMike Christensen 	 */
37830588217SMike Christensen 	ds_taskq = taskq_create("ds_taskq", 1, minclsyspri, 1,
37930588217SMike Christensen 	    DS_MAX_TASKQ_THR, TASKQ_PREPOPULATE | TASKQ_DYNAMIC);
38030588217SMike Christensen 
38130588217SMike Christensen 	/*
38230588217SMike Christensen 	 * Initialize the message log.
38330588217SMike Christensen 	 */
38430588217SMike Christensen 	ds_log_init();
38530588217SMike Christensen }
38630588217SMike Christensen 
38730588217SMike Christensen int
ds_sys_dispatch_func(void (func)(void *),void * arg)38830588217SMike Christensen ds_sys_dispatch_func(void (func)(void *), void *arg)
38930588217SMike Christensen {
390fc8ae2ecSToomas Soome 	return (DS_DISPATCH(func, arg) == TASKQID_INVALID);
39130588217SMike Christensen }
39230588217SMike Christensen 
39330588217SMike Christensen /*
39430588217SMike Christensen  * Drain event queue, if necessary.
39530588217SMike Christensen  */
39630588217SMike Christensen void
ds_sys_drain_events(ds_port_t * port)39730588217SMike Christensen ds_sys_drain_events(ds_port_t *port)
39830588217SMike Christensen {
39930588217SMike Christensen 	_NOTE(ARGUNUSED(port))
40030588217SMike Christensen }
40130588217SMike Christensen 
40230588217SMike Christensen /*
40330588217SMike Christensen  * System specific port initalization.
40430588217SMike Christensen  */
40530588217SMike Christensen void
ds_sys_port_init(ds_port_t * port)40630588217SMike Christensen ds_sys_port_init(ds_port_t *port)
40730588217SMike Christensen {
40830588217SMike Christensen 	_NOTE(ARGUNUSED(port))
40930588217SMike Christensen }
41030588217SMike Christensen 
41130588217SMike Christensen /*
41230588217SMike Christensen  * System specific port teardown.
41330588217SMike Christensen  */
41430588217SMike Christensen void
ds_sys_port_fini(ds_port_t * port)41530588217SMike Christensen ds_sys_port_fini(ds_port_t *port)
41630588217SMike Christensen {
41730588217SMike Christensen 	_NOTE(ARGUNUSED(port))
41830588217SMike Christensen }
41930588217SMike Christensen 
42030588217SMike Christensen /*
42130588217SMike Christensen  * System specific LDC channel initialization.
42230588217SMike Christensen  */
42330588217SMike Christensen void
ds_sys_ldc_init(ds_port_t * port)42430588217SMike Christensen ds_sys_ldc_init(ds_port_t *port)
42530588217SMike Christensen {
42630588217SMike Christensen 	int	rv;
42730588217SMike Christensen 	char	ebuf[DS_EBUFSIZE];
42830588217SMike Christensen 
42930588217SMike Christensen 	ASSERT(MUTEX_HELD(&port->lock));
43030588217SMike Christensen 
43130588217SMike Christensen 	if ((rv = ldc_open(port->ldc.hdl)) != 0) {
43230588217SMike Christensen 		cmn_err(CE_WARN, "ds@%lx: %s: ldc_open: %s",
43330588217SMike Christensen 		    PORTID(port), __func__, ds_errno_to_str(rv, ebuf));
43430588217SMike Christensen 		return;
43530588217SMike Christensen 	}
43630588217SMike Christensen 
43730588217SMike Christensen 	(void) ldc_up(port->ldc.hdl);
43830588217SMike Christensen 
43930588217SMike Christensen 	(void) ldc_status(port->ldc.hdl, &port->ldc.state);
44030588217SMike Christensen 
44130588217SMike Christensen 	DS_DBG_LDC(CE_NOTE, "ds@%lx: %s: initial LDC state 0x%x",
44230588217SMike Christensen 	    PORTID(port), __func__, port->ldc.state);
44330588217SMike Christensen 
44430588217SMike Christensen 	port->state = DS_PORT_LDC_INIT;
44530588217SMike Christensen }
44630588217SMike Christensen 
44730588217SMike Christensen /*
44830588217SMike Christensen  * DS message log
44930588217SMike Christensen  *
45030588217SMike Christensen  * Locking: The message log is protected by a single mutex. This
45130588217SMike Christensen  *   protects all fields in the log structure itself as well as
45230588217SMike Christensen  *   everything in the entry structures on both the log and the
45330588217SMike Christensen  *   free list.
45430588217SMike Christensen  */
45530588217SMike Christensen static struct log {
45630588217SMike Christensen 	ds_log_entry_t		*head;		/* head of the log */
45730588217SMike Christensen 	ds_log_entry_t		*freelist;	/* head of the free list */
45830588217SMike Christensen 	size_t			size;		/* size of the log in bytes */
45930588217SMike Christensen 	uint32_t		nentry;		/* number of entries */
46030588217SMike Christensen 	kmutex_t		lock;		/* log lock */
46130588217SMike Christensen } ds_log;
46230588217SMike Christensen 
46330588217SMike Christensen /* log soft limit */
46430588217SMike Christensen uint_t ds_log_sz = DS_LOG_DEFAULT_SZ;
46530588217SMike Christensen 
46630588217SMike Christensen /* initial pool of log entry structures */
46730588217SMike Christensen static ds_log_entry_t ds_log_entry_pool[DS_LOG_NPOOL];
46830588217SMike Christensen 
46930588217SMike Christensen /*
47030588217SMike Christensen  * Logging Support
47130588217SMike Christensen  */
47230588217SMike Christensen static void
ds_log_init(void)47330588217SMike Christensen ds_log_init(void)
47430588217SMike Christensen {
47530588217SMike Christensen 	/* initialize global lock */
47630588217SMike Christensen 	mutex_init(&ds_log.lock, NULL, MUTEX_DRIVER, NULL);
47730588217SMike Christensen 
47830588217SMike Christensen 	mutex_enter(&ds_log.lock);
47930588217SMike Christensen 
48030588217SMike Christensen 	/* initialize the log */
48130588217SMike Christensen 	ds_log.head = NULL;
48230588217SMike Christensen 	ds_log.size = 0;
48330588217SMike Christensen 	ds_log.nentry = 0;
48430588217SMike Christensen 
48530588217SMike Christensen 	/* initialize the free list */
486*cb453c7aSToomas Soome 	for (int i = 0; i < DS_LOG_NPOOL; i++) {
487*cb453c7aSToomas Soome 		ds_log_entry_pool[i].next = ds_log.freelist;
488*cb453c7aSToomas Soome 		ds_log.freelist = &ds_log_entry_pool[i];
48930588217SMike Christensen 	}
49030588217SMike Christensen 
49130588217SMike Christensen 	mutex_exit(&ds_log.lock);
49230588217SMike Christensen 
49330588217SMike Christensen 	DS_DBG_LOG(CE_NOTE, "ds_log initialized: size=%d bytes, "
49430588217SMike Christensen 	    " limit=%d bytes, ninit=%ld", ds_log_sz, DS_LOG_LIMIT,
49530588217SMike Christensen 	    DS_LOG_NPOOL);
49630588217SMike Christensen }
49730588217SMike Christensen 
49830588217SMike Christensen static void
ds_log_fini(void)49930588217SMike Christensen ds_log_fini(void)
50030588217SMike Christensen {
50130588217SMike Christensen 	ds_log_entry_t	*next;
50230588217SMike Christensen 
50330588217SMike Christensen 	mutex_enter(&ds_log.lock);
50430588217SMike Christensen 
50530588217SMike Christensen 	/* clear out the log */
50630588217SMike Christensen 	while (ds_log.nentry > 0)
50730588217SMike Christensen 		(void) ds_log_remove();
50830588217SMike Christensen 
50930588217SMike Christensen 	/*
51030588217SMike Christensen 	 * Now all the entries are on the free list.
51130588217SMike Christensen 	 * Clear out the free list, deallocating any
51230588217SMike Christensen 	 * entry that was dynamically allocated.
51330588217SMike Christensen 	 */
51430588217SMike Christensen 	while (ds_log.freelist != NULL) {
51530588217SMike Christensen 		next = ds_log.freelist->next;
51630588217SMike Christensen 
51730588217SMike Christensen 		if (!DS_IS_POOL_ENTRY(ds_log.freelist)) {
51830588217SMike Christensen 			kmem_free(ds_log.freelist, sizeof (ds_log_entry_t));
51930588217SMike Christensen 		}
52030588217SMike Christensen 
52130588217SMike Christensen 		ds_log.freelist = next;
52230588217SMike Christensen 	}
52330588217SMike Christensen 
52430588217SMike Christensen 	mutex_exit(&ds_log.lock);
52530588217SMike Christensen 
52630588217SMike Christensen 	mutex_destroy(&ds_log.lock);
52730588217SMike Christensen }
52830588217SMike Christensen 
52930588217SMike Christensen static ds_log_entry_t *
ds_log_entry_alloc(void)53030588217SMike Christensen ds_log_entry_alloc(void)
53130588217SMike Christensen {
53230588217SMike Christensen 	ds_log_entry_t	*new = NULL;
53330588217SMike Christensen 
53430588217SMike Christensen 	ASSERT(MUTEX_HELD(&ds_log.lock));
53530588217SMike Christensen 
53630588217SMike Christensen 	if (ds_log.freelist != NULL) {
53730588217SMike Christensen 		new = ds_log.freelist;
53830588217SMike Christensen 		ds_log.freelist = ds_log.freelist->next;
53930588217SMike Christensen 	}
54030588217SMike Christensen 
54130588217SMike Christensen 	if (new == NULL) {
54230588217SMike Christensen 		/* free list was empty */
54330588217SMike Christensen 		new = kmem_zalloc(sizeof (ds_log_entry_t), KM_SLEEP);
54430588217SMike Christensen 	}
54530588217SMike Christensen 
54630588217SMike Christensen 	ASSERT(new);
54730588217SMike Christensen 
54830588217SMike Christensen 	return (new);
54930588217SMike Christensen }
55030588217SMike Christensen 
55130588217SMike Christensen static void
ds_log_entry_free(ds_log_entry_t * entry)55230588217SMike Christensen ds_log_entry_free(ds_log_entry_t *entry)
55330588217SMike Christensen {
55430588217SMike Christensen 	ASSERT(MUTEX_HELD(&ds_log.lock));
55530588217SMike Christensen 
55630588217SMike Christensen 	if (entry == NULL)
55730588217SMike Christensen 		return;
55830588217SMike Christensen 
55930588217SMike Christensen 	if (entry->data != NULL) {
56030588217SMike Christensen 		kmem_free(entry->data, entry->datasz);
56130588217SMike Christensen 		entry->data = NULL;
56230588217SMike Christensen 	}
56330588217SMike Christensen 
56430588217SMike Christensen 	/* place entry on the free list */
56530588217SMike Christensen 	entry->next = ds_log.freelist;
56630588217SMike Christensen 	ds_log.freelist = entry;
56730588217SMike Christensen }
56830588217SMike Christensen 
56930588217SMike Christensen /*
57030588217SMike Christensen  * Add a message to the end of the log
57130588217SMike Christensen  */
57230588217SMike Christensen static int
ds_log_add(ds_log_entry_t * new)57330588217SMike Christensen ds_log_add(ds_log_entry_t *new)
57430588217SMike Christensen {
57530588217SMike Christensen 	ASSERT(MUTEX_HELD(&ds_log.lock));
57630588217SMike Christensen 
57730588217SMike Christensen 	if (ds_log.head == NULL) {
57830588217SMike Christensen 
57930588217SMike Christensen 		new->prev = new;
58030588217SMike Christensen 		new->next = new;
58130588217SMike Christensen 
58230588217SMike Christensen 		ds_log.head = new;
58330588217SMike Christensen 	} else {
58430588217SMike Christensen 		ds_log_entry_t	*head = ds_log.head;
58530588217SMike Christensen 		ds_log_entry_t	*tail = ds_log.head->prev;
58630588217SMike Christensen 
58730588217SMike Christensen 		new->next = head;
58830588217SMike Christensen 		new->prev = tail;
58930588217SMike Christensen 		tail->next = new;
59030588217SMike Christensen 		head->prev = new;
59130588217SMike Christensen 	}
59230588217SMike Christensen 
59330588217SMike Christensen 	/* increase the log size, including the metadata size */
59430588217SMike Christensen 	ds_log.size += DS_LOG_ENTRY_SZ(new);
59530588217SMike Christensen 	ds_log.nentry++;
59630588217SMike Christensen 
59730588217SMike Christensen 	DS_DBG_LOG(CE_NOTE, "ds_log: added %ld data bytes, %ld total bytes",
59830588217SMike Christensen 	    new->datasz, DS_LOG_ENTRY_SZ(new));
59930588217SMike Christensen 
60030588217SMike Christensen 	return (0);
60130588217SMike Christensen }
60230588217SMike Christensen 
60330588217SMike Christensen /*
60430588217SMike Christensen  * Remove an entry from the head of the log
60530588217SMike Christensen  */
60630588217SMike Christensen static int
ds_log_remove(void)60730588217SMike Christensen ds_log_remove(void)
60830588217SMike Christensen {
60930588217SMike Christensen 	ds_log_entry_t	*head;
61030588217SMike Christensen 
61130588217SMike Christensen 	ASSERT(MUTEX_HELD(&ds_log.lock));
61230588217SMike Christensen 
61330588217SMike Christensen 	head = ds_log.head;
61430588217SMike Christensen 
61530588217SMike Christensen 	/* empty list */
61630588217SMike Christensen 	if (head == NULL)
61730588217SMike Christensen 		return (0);
61830588217SMike Christensen 
61930588217SMike Christensen 	if (head->next == ds_log.head) {
62030588217SMike Christensen 		/* one element list */
62130588217SMike Christensen 		ds_log.head = NULL;
62230588217SMike Christensen 	} else {
62330588217SMike Christensen 		head->next->prev = head->prev;
62430588217SMike Christensen 		head->prev->next = head->next;
62530588217SMike Christensen 		ds_log.head = head->next;
62630588217SMike Christensen 	}
62730588217SMike Christensen 
62830588217SMike Christensen 	DS_DBG_LOG(CE_NOTE, "ds_log: removed %ld data bytes, %ld total bytes",
62930588217SMike Christensen 	    head->datasz, DS_LOG_ENTRY_SZ(head));
63030588217SMike Christensen 
63130588217SMike Christensen 	ds_log.size -= DS_LOG_ENTRY_SZ(head);
63230588217SMike Christensen 	ds_log.nentry--;
63330588217SMike Christensen 
63430588217SMike Christensen 	ds_log_entry_free(head);
63530588217SMike Christensen 
63630588217SMike Christensen 	return (0);
63730588217SMike Christensen }
63830588217SMike Christensen 
63930588217SMike Christensen /*
64030588217SMike Christensen  * Replace the data in the entry at the front of the list with then
64130588217SMike Christensen  * new data. This has the effect of removing the oldest entry and
64230588217SMike Christensen  * adding the new entry.
64330588217SMike Christensen  */
64430588217SMike Christensen static int
ds_log_replace(int32_t dest,uint8_t * msg,size_t sz)64530588217SMike Christensen ds_log_replace(int32_t dest, uint8_t *msg, size_t sz)
64630588217SMike Christensen {
64730588217SMike Christensen 	ds_log_entry_t	*head;
64830588217SMike Christensen 
64930588217SMike Christensen 	ASSERT(MUTEX_HELD(&ds_log.lock));
65030588217SMike Christensen 
65130588217SMike Christensen 	head = ds_log.head;
65230588217SMike Christensen 
65330588217SMike Christensen 	DS_DBG_LOG(CE_NOTE, "ds_log: replaced %ld data bytes (%ld total) with "
65430588217SMike Christensen 	    " %ld data bytes (%ld total)", head->datasz,
65530588217SMike Christensen 	    DS_LOG_ENTRY_SZ(head), sz, sz + sizeof (ds_log_entry_t));
65630588217SMike Christensen 
65730588217SMike Christensen 	ds_log.size -= DS_LOG_ENTRY_SZ(head);
65830588217SMike Christensen 
65930588217SMike Christensen 	kmem_free(head->data, head->datasz);
66030588217SMike Christensen 
66130588217SMike Christensen 	head->data = msg;
66230588217SMike Christensen 	head->datasz = sz;
66330588217SMike Christensen 	head->timestamp = ddi_get_time();
66430588217SMike Christensen 	head->dest = dest;
66530588217SMike Christensen 
66630588217SMike Christensen 	ds_log.size += DS_LOG_ENTRY_SZ(head);
66730588217SMike Christensen 
66830588217SMike Christensen 	ds_log.head = head->next;
66930588217SMike Christensen 
67030588217SMike Christensen 	return (0);
67130588217SMike Christensen }
67230588217SMike Christensen 
67330588217SMike Christensen static void
ds_log_purge(void * arg)67430588217SMike Christensen ds_log_purge(void *arg)
67530588217SMike Christensen {
67630588217SMike Christensen 	_NOTE(ARGUNUSED(arg))
67730588217SMike Christensen 
67830588217SMike Christensen 	mutex_enter(&ds_log.lock);
67930588217SMike Christensen 
68030588217SMike Christensen 	DS_DBG_LOG(CE_NOTE, "ds_log: purging oldest log entries");
68130588217SMike Christensen 
68230588217SMike Christensen 	while ((ds_log.nentry) && (ds_log.size >= ds_log_sz)) {
68330588217SMike Christensen 		(void) ds_log_remove();
68430588217SMike Christensen 	}
68530588217SMike Christensen 
68630588217SMike Christensen 	mutex_exit(&ds_log.lock);
68730588217SMike Christensen }
68830588217SMike Christensen 
68930588217SMike Christensen int
ds_log_add_msg(int32_t dest,uint8_t * msg,size_t sz)69030588217SMike Christensen ds_log_add_msg(int32_t dest, uint8_t *msg, size_t sz)
69130588217SMike Christensen {
69230588217SMike Christensen 	int	rv = 0;
69330588217SMike Christensen 	void	*data;
69430588217SMike Christensen 
69530588217SMike Christensen 	mutex_enter(&ds_log.lock);
69630588217SMike Christensen 
69730588217SMike Christensen 	/* allocate a local copy of the data */
69830588217SMike Christensen 	data = kmem_alloc(sz, KM_SLEEP);
69930588217SMike Christensen 	bcopy(msg, data, sz);
70030588217SMike Christensen 
70130588217SMike Christensen 	/* check if the log is larger than the soft limit */
70230588217SMike Christensen 	if ((ds_log.nentry) && ((ds_log.size + sz) >= ds_log_sz)) {
70330588217SMike Christensen 		/*
70430588217SMike Christensen 		 * The log is larger than the soft limit.
70530588217SMike Christensen 		 * Swap the oldest entry for the newest.
70630588217SMike Christensen 		 */
70730588217SMike Christensen 		DS_DBG_LOG(CE_NOTE, "%s: replacing oldest entry with new entry",
70830588217SMike Christensen 		    __func__);
70930588217SMike Christensen 		(void) ds_log_replace(dest, data, sz);
71030588217SMike Christensen 	} else {
71130588217SMike Christensen 		/*
71230588217SMike Christensen 		 * Still have headroom under the soft limit.
71330588217SMike Christensen 		 * Add the new entry to the log.
71430588217SMike Christensen 		 */
71530588217SMike Christensen 		ds_log_entry_t	*new;
71630588217SMike Christensen 
71730588217SMike Christensen 		new = ds_log_entry_alloc();
71830588217SMike Christensen 
71930588217SMike Christensen 		/* fill in message data */
72030588217SMike Christensen 		new->data = data;
72130588217SMike Christensen 		new->datasz = sz;
72230588217SMike Christensen 		new->timestamp = ddi_get_time();
72330588217SMike Christensen 		new->dest = dest;
72430588217SMike Christensen 
72530588217SMike Christensen 		rv = ds_log_add(new);
72630588217SMike Christensen 	}
72730588217SMike Christensen 
72830588217SMike Christensen 	/* check if the log is larger than the hard limit */
72930588217SMike Christensen 	if ((ds_log.nentry > 1) && (ds_log.size >= DS_LOG_LIMIT)) {
73030588217SMike Christensen 		/*
73130588217SMike Christensen 		 * Wakeup the thread to remove entries
73230588217SMike Christensen 		 * from the log until it is smaller than
73330588217SMike Christensen 		 * the soft limit.
73430588217SMike Christensen 		 */
73530588217SMike Christensen 		DS_DBG_LOG(CE_NOTE, "%s: log exceeded %d bytes, scheduling"
73630588217SMike Christensen 		    " a purge...", __func__, DS_LOG_LIMIT);
73730588217SMike Christensen 
738fc8ae2ecSToomas Soome 		if (DS_DISPATCH(ds_log_purge, NULL) == TASKQID_INVALID) {
73930588217SMike Christensen 			cmn_err(CE_NOTE, "%s: purge thread failed to start",
74030588217SMike Christensen 			    __func__);
74130588217SMike Christensen 		}
74230588217SMike Christensen 	}
74330588217SMike Christensen 
74430588217SMike Christensen 	mutex_exit(&ds_log.lock);
74530588217SMike Christensen 
74630588217SMike Christensen 	return (rv);
74730588217SMike Christensen }
74830588217SMike Christensen 
74930588217SMike Christensen int
ds_add_port(uint64_t port_id,uint64_t ldc_id,ds_domain_hdl_t dhdl,char * dom_name,int verbose)75030588217SMike Christensen ds_add_port(uint64_t port_id, uint64_t ldc_id, ds_domain_hdl_t dhdl,
75130588217SMike Christensen     char *dom_name, int verbose)
75230588217SMike Christensen {
75330588217SMike Christensen 	ds_port_t	*newport;
75430588217SMike Christensen 
75530588217SMike Christensen 	/* sanity check the port id */
75630588217SMike Christensen 	if (port_id > DS_MAX_PORT_ID) {
75730588217SMike Christensen 		cmn_err(CE_WARN, "%s: port ID %ld out of range",
75830588217SMike Christensen 		    __func__, port_id);
75930588217SMike Christensen 		return (EINVAL);
76030588217SMike Christensen 	}
76130588217SMike Christensen 
762a600f50dSMike Christensen 	DS_DBG_MD(CE_NOTE, "%s: adding port ds@%ld, LDC: 0x%lx, dhdl: 0x%lx "
763a600f50dSMike Christensen 	    "name: '%s'", __func__, port_id, ldc_id, dhdl,
764a600f50dSMike Christensen 	    dom_name == NULL ? "NULL" : dom_name);
76530588217SMike Christensen 
76630588217SMike Christensen 	/* get the port structure from the array of ports */
76730588217SMike Christensen 	newport = &ds_ports[port_id];
76830588217SMike Christensen 
76930588217SMike Christensen 	/* check for a duplicate port in the MD */
77030588217SMike Christensen 	if (newport->state != DS_PORT_FREE) {
77130588217SMike Christensen 		if (verbose) {
77230588217SMike Christensen 			cmn_err(CE_WARN, "ds@%lx: %s: port already exists",
77330588217SMike Christensen 			    port_id, __func__);
77430588217SMike Christensen 		}
77530588217SMike Christensen 		if (newport->domain_hdl == DS_DHDL_INVALID) {
77630588217SMike Christensen 			newport->domain_hdl = dhdl;
77730588217SMike Christensen 		}
77830588217SMike Christensen 		if (newport->domain_name == NULL && dom_name != NULL) {
77930588217SMike Christensen 			newport->domain_name = ds_strdup(dom_name);
78030588217SMike Christensen 		}
78130588217SMike Christensen 		return (EBUSY);
78230588217SMike Christensen 	}
78330588217SMike Christensen 
78430588217SMike Christensen 	/* initialize the port */
78530588217SMike Christensen 	newport->id = port_id;
78630588217SMike Christensen 	newport->ldc.id = ldc_id;
78730588217SMike Christensen 	newport->domain_hdl = dhdl;
78830588217SMike Christensen 	if (dom_name) {
78930588217SMike Christensen 		newport->domain_name = ds_strdup(dom_name);
79030588217SMike Christensen 	} else
79130588217SMike Christensen 		newport->domain_name = NULL;
79230588217SMike Christensen 	ds_port_common_init(newport);
79330588217SMike Christensen 
79430588217SMike Christensen 	return (0);
79530588217SMike Christensen }
79630588217SMike Christensen 
797beba1dd8SMike Christensen /* ARGSUSED */
79830588217SMike Christensen int
ds_remove_port(uint64_t port_id,int is_fini)79930588217SMike Christensen ds_remove_port(uint64_t port_id, int is_fini)
80030588217SMike Christensen {
80130588217SMike Christensen 	ds_port_t *port;
80230588217SMike Christensen 
80330588217SMike Christensen 	if (port_id >= DS_MAX_PORTS || !DS_PORT_IN_SET(ds_allports, port_id)) {
80430588217SMike Christensen 		DS_DBG_MD(CE_NOTE, "%s: invalid port %lx", __func__,
80530588217SMike Christensen 		    port_id);
80630588217SMike Christensen 		return (EINVAL);
80730588217SMike Christensen 	}
80830588217SMike Christensen 
80930588217SMike Christensen 	DS_DBG_MD(CE_NOTE, "%s: removing port ds@%lx", __func__, port_id);
81030588217SMike Christensen 
81130588217SMike Christensen 	port = &ds_ports[port_id];
81230588217SMike Christensen 
81330588217SMike Christensen 	mutex_enter(&port->lock);
81430588217SMike Christensen 
81530588217SMike Christensen 	if (port->state >= DS_PORT_LDC_INIT) {
81630588217SMike Christensen 		/* shut down the LDC for this port */
81730588217SMike Christensen 		(void) ds_ldc_fini(port);
81830588217SMike Christensen 	}
81930588217SMike Christensen 
82030588217SMike Christensen 	if (port->domain_name) {
82130588217SMike Christensen 		DS_FREE(port->domain_name, strlen(port->domain_name) + 1);
82230588217SMike Christensen 		port->domain_name = NULL;
82330588217SMike Christensen 	}
82430588217SMike Christensen 	port->domain_hdl = DS_DHDL_INVALID;
82530588217SMike Christensen 
82630588217SMike Christensen 	/* clean up the port structure */
827beba1dd8SMike Christensen 	ds_port_common_fini(port);
828beba1dd8SMike Christensen 
829beba1dd8SMike Christensen 	mutex_exit(&port->lock);
83030588217SMike Christensen 	return (0);
83130588217SMike Christensen }
83230588217SMike Christensen 
83330588217SMike Christensen /*
83430588217SMike Christensen  * Interface for ds_service_lookup in lds driver.
83530588217SMike Christensen  */
83630588217SMike Christensen int
ds_service_lookup(ds_svc_hdl_t hdl,char ** servicep,uint_t * is_client)83730588217SMike Christensen ds_service_lookup(ds_svc_hdl_t hdl, char **servicep, uint_t *is_client)
83830588217SMike Christensen {
83930588217SMike Christensen 	ds_svc_t	*svc;
84030588217SMike Christensen 
84130588217SMike Christensen 	mutex_enter(&ds_svcs.lock);
84230588217SMike Christensen 	if ((svc = ds_get_svc(hdl)) == NULL) {
84330588217SMike Christensen 		mutex_exit(&ds_svcs.lock);
84430588217SMike Christensen 		DS_DBG(CE_NOTE, "%s: handle 0x%llx not found", __func__,
84530588217SMike Christensen 		    (u_longlong_t)hdl);
84630588217SMike Christensen 		return (ENXIO);
84730588217SMike Christensen 	}
84830588217SMike Christensen 	*servicep = svc->cap.svc_id;
84930588217SMike Christensen 	*is_client = svc->flags & DSSF_ISCLIENT;
85030588217SMike Christensen 	mutex_exit(&ds_svcs.lock);
85130588217SMike Christensen 	return (0);
85230588217SMike Christensen }
85330588217SMike Christensen 
85430588217SMike Christensen /*
85530588217SMike Christensen  * Interface for ds_domain_lookup in lds driver.
85630588217SMike Christensen  */
85730588217SMike Christensen int
ds_domain_lookup(ds_svc_hdl_t hdl,ds_domain_hdl_t * dhdlp)85830588217SMike Christensen ds_domain_lookup(ds_svc_hdl_t hdl, ds_domain_hdl_t *dhdlp)
85930588217SMike Christensen {
86030588217SMike Christensen 	ds_svc_t	*svc;
86130588217SMike Christensen 
86230588217SMike Christensen 	mutex_enter(&ds_svcs.lock);
86330588217SMike Christensen 	if ((svc = ds_get_svc(hdl)) == NULL) {
86430588217SMike Christensen 		mutex_exit(&ds_svcs.lock);
86530588217SMike Christensen 		DS_DBG(CE_NOTE, "%s: handle 0x%llx not found", __func__,
86630588217SMike Christensen 		    (u_longlong_t)hdl);
86730588217SMike Christensen 		return (ENXIO);
86830588217SMike Christensen 	}
86930588217SMike Christensen 	if (svc->port == NULL)
87030588217SMike Christensen 		*dhdlp = ds_my_domain_hdl;
87130588217SMike Christensen 	else
87230588217SMike Christensen 		*dhdlp = svc->port->domain_hdl;
87330588217SMike Christensen 	mutex_exit(&ds_svcs.lock);
87430588217SMike Christensen 	return (0);
87530588217SMike Christensen }
87630588217SMike Christensen 
87730588217SMike Christensen /*
87830588217SMike Christensen  * Interface for ds_hdl_isready in lds driver.
87930588217SMike Christensen  */
88030588217SMike Christensen int
ds_hdl_isready(ds_svc_hdl_t hdl,uint_t * is_ready)88130588217SMike Christensen ds_hdl_isready(ds_svc_hdl_t hdl, uint_t *is_ready)
88230588217SMike Christensen {
88330588217SMike Christensen 	ds_svc_t	*svc;
88430588217SMike Christensen 
88530588217SMike Christensen 	mutex_enter(&ds_svcs.lock);
88630588217SMike Christensen 	if ((svc = ds_get_svc(hdl)) == NULL) {
88730588217SMike Christensen 		mutex_exit(&ds_svcs.lock);
88830588217SMike Christensen 		DS_DBG(CE_NOTE, "%s: handle 0x%llx not found", __func__,
88930588217SMike Christensen 		    (u_longlong_t)hdl);
89030588217SMike Christensen 		return (ENXIO);
89130588217SMike Christensen 	}
89230588217SMike Christensen 	*is_ready = (svc->state == DS_SVC_ACTIVE);
89330588217SMike Christensen 	mutex_exit(&ds_svcs.lock);
89430588217SMike Christensen 	return (0);
89530588217SMike Christensen }
89630588217SMike Christensen 
89730588217SMike Christensen /*
89830588217SMike Christensen  * Interface for ds_dom_name_to_hdl in lds driver.
89930588217SMike Christensen  */
90030588217SMike Christensen int
ds_dom_name_to_hdl(char * domain_name,ds_domain_hdl_t * dhdlp)90130588217SMike Christensen ds_dom_name_to_hdl(char *domain_name, ds_domain_hdl_t *dhdlp)
90230588217SMike Christensen {
90330588217SMike Christensen 	int i;
90430588217SMike Christensen 	ds_port_t *port;
90530588217SMike Christensen 
906a600f50dSMike Christensen 	if (domain_name == NULL) {
907a600f50dSMike Christensen 		return (ENXIO);
908a600f50dSMike Christensen 	}
909a600f50dSMike Christensen 	if (ds_my_domain_name != NULL &&
910a600f50dSMike Christensen 	    strcmp(ds_my_domain_name, domain_name) == 0) {
911a600f50dSMike Christensen 		*dhdlp = ds_my_domain_hdl;
912a600f50dSMike Christensen 		return (0);
913a600f50dSMike Christensen 	}
91430588217SMike Christensen 	for (i = 0, port = ds_ports; i < DS_MAX_PORTS; i++, port++) {
91530588217SMike Christensen 		if (port->state != DS_PORT_FREE &&
91630588217SMike Christensen 		    port->domain_name != NULL &&
91730588217SMike Christensen 		    strcmp(port->domain_name, domain_name) == 0) {
91830588217SMike Christensen 			*dhdlp = port->domain_hdl;
91930588217SMike Christensen 			return (0);
92030588217SMike Christensen 		}
92130588217SMike Christensen 	}
92230588217SMike Christensen 	return (ENXIO);
92330588217SMike Christensen }
92430588217SMike Christensen 
92530588217SMike Christensen /*
92630588217SMike Christensen  * Interface for ds_dom_hdl_to_name in lds driver.
92730588217SMike Christensen  */
92830588217SMike Christensen int
ds_dom_hdl_to_name(ds_domain_hdl_t dhdl,char ** domain_namep)92930588217SMike Christensen ds_dom_hdl_to_name(ds_domain_hdl_t dhdl, char **domain_namep)
93030588217SMike Christensen {
93130588217SMike Christensen 	int i;
93230588217SMike Christensen 	ds_port_t *port;
93330588217SMike Christensen 
934a600f50dSMike Christensen 	if (dhdl == ds_my_domain_hdl) {
935a600f50dSMike Christensen 		if (ds_my_domain_name != NULL) {
936a600f50dSMike Christensen 			*domain_namep = ds_my_domain_name;
937a600f50dSMike Christensen 			return (0);
938a600f50dSMike Christensen 		}
939a600f50dSMike Christensen 		return (ENXIO);
940a600f50dSMike Christensen 	}
94130588217SMike Christensen 	for (i = 0, port = ds_ports; i < DS_MAX_PORTS; i++, port++) {
94230588217SMike Christensen 		if (port->state != DS_PORT_FREE &&
94330588217SMike Christensen 		    port->domain_hdl == dhdl) {
94430588217SMike Christensen 			*domain_namep = port->domain_name;
94530588217SMike Christensen 			return (0);
94630588217SMike Christensen 		}
94730588217SMike Christensen 	}
94830588217SMike Christensen 	return (ENXIO);
94930588217SMike Christensen }
95030588217SMike Christensen 
95130588217SMike Christensen /*
95230588217SMike Christensen  * Unregister all handles related to device open instance.
95330588217SMike Christensen  */
95430588217SMike Christensen void
ds_unreg_all(int instance)95530588217SMike Christensen ds_unreg_all(int instance)
95630588217SMike Christensen {
95730588217SMike Christensen 	int		idx;
95830588217SMike Christensen 	ds_svc_t	*svc;
95930588217SMike Christensen 	ds_svc_hdl_t	hdl;
96030588217SMike Christensen 
96130588217SMike Christensen 	DS_DBG_USR(CE_NOTE, "%s: entered", __func__);
96230588217SMike Christensen 
96330588217SMike Christensen 	/* walk every table entry */
96430588217SMike Christensen 	mutex_enter(&ds_svcs.lock);
96530588217SMike Christensen 	for (idx = 0; idx < ds_svcs.maxsvcs; idx++) {
96630588217SMike Christensen 		svc = ds_svcs.tbl[idx];
96730588217SMike Christensen 		if (DS_SVC_ISFREE(svc))
96830588217SMike Christensen 			continue;
96930588217SMike Christensen 		if ((svc->flags & DSSF_ISUSER) != 0 && svc->drvi == instance) {
97030588217SMike Christensen 			hdl = svc->hdl;
97130588217SMike Christensen 			mutex_exit(&ds_svcs.lock);
97230588217SMike Christensen 			(void) ds_unreg_hdl(hdl);
97330588217SMike Christensen 			mutex_enter(&ds_svcs.lock);
97430588217SMike Christensen 			DS_DBG_USR(CE_NOTE, "%s: ds_unreg_hdl(0x%llx):",
97530588217SMike Christensen 			    __func__, (u_longlong_t)hdl);
97630588217SMike Christensen 		}
97730588217SMike Christensen 	}
97830588217SMike Christensen 	mutex_exit(&ds_svcs.lock);
97930588217SMike Christensen }
98030588217SMike Christensen 
98130588217SMike Christensen /*
98230588217SMike Christensen  * Special callbacks to allow the lds module revision-independent access
98330588217SMike Christensen  * to service structure data in the callback routines.  This assumes that
98430588217SMike Christensen  * we put a special "cookie" in the arg argument passed to those
98530588217SMike Christensen  * routines (for now, a ptr to the svc structure, but it could be a svc
98630588217SMike Christensen  * table index or something that we could get back to the svc table entry).
98730588217SMike Christensen  */
98830588217SMike Christensen void
ds_cbarg_get_hdl(ds_cb_arg_t arg,ds_svc_hdl_t * hdlp)98930588217SMike Christensen ds_cbarg_get_hdl(ds_cb_arg_t arg, ds_svc_hdl_t *hdlp)
99030588217SMike Christensen {
99130588217SMike Christensen 	ds_svc_t *svc = (ds_svc_t *)arg;
99230588217SMike Christensen 
99330588217SMike Christensen 	ASSERT(svc == (ds_svc_t *)svc->ops.cb_arg);
99430588217SMike Christensen 	*hdlp = svc->hdl;
99530588217SMike Christensen }
99630588217SMike Christensen 
99730588217SMike Christensen void
ds_cbarg_get_flags(ds_cb_arg_t arg,uint32_t * flagsp)99830588217SMike Christensen ds_cbarg_get_flags(ds_cb_arg_t arg, uint32_t *flagsp)
99930588217SMike Christensen {
100030588217SMike Christensen 	ds_svc_t *svc = (ds_svc_t *)arg;
100130588217SMike Christensen 
100230588217SMike Christensen 	ASSERT(svc == (ds_svc_t *)svc->ops.cb_arg);
100330588217SMike Christensen 	*flagsp = svc->flags;
100430588217SMike Christensen }
100530588217SMike Christensen 
100630588217SMike Christensen void
ds_cbarg_get_drv_info(ds_cb_arg_t arg,int * drvip)100730588217SMike Christensen ds_cbarg_get_drv_info(ds_cb_arg_t arg, int *drvip)
100830588217SMike Christensen {
100930588217SMike Christensen 	ds_svc_t *svc = (ds_svc_t *)arg;
101030588217SMike Christensen 
101130588217SMike Christensen 	ASSERT(svc == (ds_svc_t *)svc->ops.cb_arg);
101230588217SMike Christensen 	*drvip = svc->drvi;
101330588217SMike Christensen }
101430588217SMike Christensen 
101530588217SMike Christensen void
ds_cbarg_get_drv_per_svc_ptr(ds_cb_arg_t arg,void ** dpspp)101630588217SMike Christensen ds_cbarg_get_drv_per_svc_ptr(ds_cb_arg_t arg, void **dpspp)
101730588217SMike Christensen {
101830588217SMike Christensen 	ds_svc_t *svc = (ds_svc_t *)arg;
101930588217SMike Christensen 
102030588217SMike Christensen 	ASSERT(svc == (ds_svc_t *)svc->ops.cb_arg);
102130588217SMike Christensen 	*dpspp = svc->drv_psp;
102230588217SMike Christensen }
102330588217SMike Christensen 
102430588217SMike Christensen void
ds_cbarg_get_domain(ds_cb_arg_t arg,ds_domain_hdl_t * dhdlp)102530588217SMike Christensen ds_cbarg_get_domain(ds_cb_arg_t arg, ds_domain_hdl_t *dhdlp)
102630588217SMike Christensen {
102730588217SMike Christensen 	ds_svc_t *svc = (ds_svc_t *)arg;
102830588217SMike Christensen 
102930588217SMike Christensen 	ASSERT(svc == (ds_svc_t *)svc->ops.cb_arg);
103030588217SMike Christensen 	if (svc->port == NULL)
103130588217SMike Christensen 		*dhdlp = ds_my_domain_hdl;
103230588217SMike Christensen 	else
103330588217SMike Christensen 		*dhdlp = svc->port->domain_hdl;
103430588217SMike Christensen }
103530588217SMike Christensen 
103630588217SMike Christensen void
ds_cbarg_get_service_id(ds_cb_arg_t arg,char ** servicep)103730588217SMike Christensen ds_cbarg_get_service_id(ds_cb_arg_t arg, char **servicep)
103830588217SMike Christensen {
103930588217SMike Christensen 	ds_svc_t *svc = (ds_svc_t *)arg;
104030588217SMike Christensen 
104130588217SMike Christensen 	ASSERT(svc == (ds_svc_t *)svc->ops.cb_arg);
104230588217SMike Christensen 	*servicep = svc->cap.svc_id;
104330588217SMike Christensen }
104430588217SMike Christensen 
104530588217SMike Christensen void
ds_cbarg_set_drv_per_svc_ptr(ds_cb_arg_t arg,void * dpsp)104630588217SMike Christensen ds_cbarg_set_drv_per_svc_ptr(ds_cb_arg_t arg, void *dpsp)
104730588217SMike Christensen {
104830588217SMike Christensen 	ds_svc_t *svc = (ds_svc_t *)arg;
104930588217SMike Christensen 
105030588217SMike Christensen 	ASSERT(svc == (ds_svc_t *)svc->ops.cb_arg);
105130588217SMike Christensen 	svc->drv_psp = dpsp;
105230588217SMike Christensen }
105330588217SMike Christensen 
105430588217SMike Christensen void
ds_cbarg_set_cookie(ds_svc_t * svc)105530588217SMike Christensen ds_cbarg_set_cookie(ds_svc_t *svc)
105630588217SMike Christensen {
105730588217SMike Christensen 	svc->ops.cb_arg = (ds_cb_arg_t)(svc);
105830588217SMike Christensen }
105930588217SMike Christensen 
106030588217SMike Christensen int
ds_hdl_get_cbarg(ds_svc_hdl_t hdl,ds_cb_arg_t * cbargp)106130588217SMike Christensen ds_hdl_get_cbarg(ds_svc_hdl_t hdl, ds_cb_arg_t *cbargp)
106230588217SMike Christensen {
106330588217SMike Christensen 	ds_svc_t *svc;
106430588217SMike Christensen 
106530588217SMike Christensen 	mutex_enter(&ds_svcs.lock);
106630588217SMike Christensen 	if ((svc = ds_get_svc(hdl)) != NULL &&
106730588217SMike Christensen 	    (svc->flags & DSSF_ISUSER) != 0) {
106830588217SMike Christensen 		ASSERT(svc == (ds_svc_t *)svc->ops.cb_arg);
106930588217SMike Christensen 		*cbargp = svc->ops.cb_arg;
107030588217SMike Christensen 		mutex_exit(&ds_svcs.lock);
107130588217SMike Christensen 		return (0);
107230588217SMike Christensen 	}
107330588217SMike Christensen 	mutex_exit(&ds_svcs.lock);
107430588217SMike Christensen 	return (ENXIO);
107530588217SMike Christensen }
107630588217SMike Christensen 
107730588217SMike Christensen int
ds_is_my_hdl(ds_svc_hdl_t hdl,int instance)107830588217SMike Christensen ds_is_my_hdl(ds_svc_hdl_t hdl, int instance)
107930588217SMike Christensen {
108030588217SMike Christensen 	ds_svc_t *svc;
108130588217SMike Christensen 	int rv = 0;
108230588217SMike Christensen 
108330588217SMike Christensen 	mutex_enter(&ds_svcs.lock);
108430588217SMike Christensen 	if ((svc = ds_get_svc(hdl)) == NULL) {
108530588217SMike Christensen 		DS_DBG_USR(CE_NOTE, "%s: invalid hdl: 0x%llx\n", __func__,
108630588217SMike Christensen 		    (u_longlong_t)hdl);
108730588217SMike Christensen 		rv = ENXIO;
108830588217SMike Christensen 	} else if (instance == DS_INVALID_INSTANCE) {
108930588217SMike Christensen 		if ((svc->flags & DSSF_ISUSER) != 0) {
109030588217SMike Christensen 			DS_DBG_USR(CE_NOTE, "%s: unowned hdl: 0x%llx\n",
109130588217SMike Christensen 			    __func__, (u_longlong_t)hdl);
109230588217SMike Christensen 			rv = EACCES;
109330588217SMike Christensen 		}
109430588217SMike Christensen 	} else if ((svc->flags & DSSF_ISUSER) == 0 || svc->drvi != instance) {
109530588217SMike Christensen 		DS_DBG_USR(CE_NOTE, "%s: unowned hdl: 0x%llx\n", __func__,
109630588217SMike Christensen 		    (u_longlong_t)hdl);
109730588217SMike Christensen 		rv = EACCES;
109830588217SMike Christensen 	}
109930588217SMike Christensen 	mutex_exit(&ds_svcs.lock);
110030588217SMike Christensen 	return (rv);
110130588217SMike Christensen }
1102