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