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
_init(void)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
_info(struct modinfo * modinfop)15730588217SMike Christensen _info(struct modinfo *modinfop)
15830588217SMike Christensen {
15930588217SMike Christensen return (mod_info(&modlinkage, modinfop));
16030588217SMike Christensen }
16130588217SMike Christensen
16230588217SMike Christensen int
_fini(void)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
ds_fini(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
ds_ports_init(void)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
ds_ports_fini(void)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
ds_port_add(md_t * mdp,mde_cookie_t port,mde_cookie_t chan)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
ds_set_my_dom_hdl_name(ds_domain_hdl_t dhdl,char * name)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
ds_init()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
ds_sys_dispatch_func(void (func)(void *),void * arg)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
ds_sys_drain_events(ds_port_t * port)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
ds_sys_port_init(ds_port_t * port)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
ds_sys_port_fini(ds_port_t * port)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
ds_sys_ldc_init(ds_port_t * port)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
ds_log_init(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
ds_log_fini(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 *
ds_log_entry_alloc(void)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
ds_log_entry_free(ds_log_entry_t * entry)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
ds_log_add(ds_log_entry_t * new)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
ds_log_remove(void)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
ds_log_replace(int32_t dest,uint8_t * msg,size_t sz)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
ds_log_purge(void * arg)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
ds_log_add_msg(int32_t dest,uint8_t * msg,size_t sz)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
ds_add_port(uint64_t port_id,uint64_t ldc_id,ds_domain_hdl_t dhdl,char * dom_name,int verbose)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
ds_remove_port(uint64_t port_id,int is_fini)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
ds_service_lookup(ds_svc_hdl_t hdl,char ** servicep,uint_t * is_client)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
ds_domain_lookup(ds_svc_hdl_t hdl,ds_domain_hdl_t * dhdlp)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
ds_hdl_isready(ds_svc_hdl_t hdl,uint_t * is_ready)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
ds_dom_name_to_hdl(char * domain_name,ds_domain_hdl_t * dhdlp)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
ds_dom_hdl_to_name(ds_domain_hdl_t dhdl,char ** domain_namep)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
ds_unreg_all(int instance)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
ds_cbarg_get_hdl(ds_cb_arg_t arg,ds_svc_hdl_t * hdlp)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
ds_cbarg_get_flags(ds_cb_arg_t arg,uint32_t * flagsp)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
ds_cbarg_get_drv_info(ds_cb_arg_t arg,int * drvip)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
ds_cbarg_get_drv_per_svc_ptr(ds_cb_arg_t arg,void ** dpspp)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
ds_cbarg_get_domain(ds_cb_arg_t arg,ds_domain_hdl_t * dhdlp)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
ds_cbarg_get_service_id(ds_cb_arg_t arg,char ** servicep)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
ds_cbarg_set_drv_per_svc_ptr(ds_cb_arg_t arg,void * dpsp)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
ds_cbarg_set_cookie(ds_svc_t * svc)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
ds_hdl_get_cbarg(ds_svc_hdl_t hdl,ds_cb_arg_t * cbargp)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
ds_is_my_hdl(ds_svc_hdl_t hdl,int instance)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