11ae08745Sheppo /*
21ae08745Sheppo  * CDDL HEADER START
31ae08745Sheppo  *
41ae08745Sheppo  * The contents of this file are subject to the terms of the
51ae08745Sheppo  * Common Development and Distribution License (the "License").
61ae08745Sheppo  * You may not use this file except in compliance with the License.
71ae08745Sheppo  *
81ae08745Sheppo  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
91ae08745Sheppo  * or http://www.opensolaris.org/os/licensing.
101ae08745Sheppo  * See the License for the specific language governing permissions
111ae08745Sheppo  * and limitations under the License.
121ae08745Sheppo  *
131ae08745Sheppo  * When distributing Covered Code, include this CDDL HEADER in each
141ae08745Sheppo  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
151ae08745Sheppo  * If applicable, add the following below this CDDL HEADER, with the
161ae08745Sheppo  * fields enclosed by brackets "[]" replaced with your own identifying
171ae08745Sheppo  * information: Portions Copyright [yyyy] [name of copyright owner]
181ae08745Sheppo  *
191ae08745Sheppo  * CDDL HEADER END
201ae08745Sheppo  */
211ae08745Sheppo 
221ae08745Sheppo /*
23*d3d50737SRafael Vanoni  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
241ae08745Sheppo  * Use is subject to license terms.
251ae08745Sheppo  */
261ae08745Sheppo 
271ae08745Sheppo #include <sys/types.h>
281ae08745Sheppo #include <sys/ddi.h>
291ae08745Sheppo #include <sys/sunddi.h>
301ae08745Sheppo #include <sys/promif_impl.h>
311ae08745Sheppo #include <sys/ds.h>
321ae08745Sheppo #include <sys/modctl.h>
331ae08745Sheppo #include <sys/ksynch.h>
341ae08745Sheppo #include <sys/varconfig.h>
351ae08745Sheppo 
361ae08745Sheppo #ifndef _KMDB
371ae08745Sheppo 
381ae08745Sheppo #define	PROMIF_DS_TIMEOUT_SEC 15
391ae08745Sheppo 
401ae08745Sheppo static kmutex_t promif_prop_lock;
411ae08745Sheppo static kcondvar_t promif_prop_cv;
421ae08745Sheppo static var_config_msg_t promif_ds_resp;
431ae08745Sheppo static var_config_resp_t *cfg_rsp = &promif_ds_resp.var_config_resp;
441ae08745Sheppo static int (*ds_send)();
451ae08745Sheppo static int (*ds_init)();
461ae08745Sheppo 
471ae08745Sheppo /*
481ae08745Sheppo  * Domains Services interaction
491ae08745Sheppo  */
501ae08745Sheppo static ds_svc_hdl_t	ds_primary_handle;
511ae08745Sheppo static ds_svc_hdl_t	ds_backup_handle;
521ae08745Sheppo 
531ae08745Sheppo static ds_ver_t		vc_version[] = { { 1, 0 } };
541ae08745Sheppo 
551ae08745Sheppo #define	VC_NVERS	(sizeof (vc_version) / sizeof (vc_version[0]))
561ae08745Sheppo 
571ae08745Sheppo static ds_capability_t vc_primary_cap = {
581ae08745Sheppo 	"var-config",		/* svc_id */
591ae08745Sheppo 	vc_version,		/* vers */
601ae08745Sheppo 	VC_NVERS		/* nvers */
611ae08745Sheppo };
621ae08745Sheppo 
631ae08745Sheppo static ds_capability_t vc_backup_cap = {
641ae08745Sheppo 	"var-config-backup",	/* svc_id */
651ae08745Sheppo 	vc_version,		/* vers */
661ae08745Sheppo 	VC_NVERS		/* nvers */
671ae08745Sheppo };
681ae08745Sheppo 
691ae08745Sheppo static void vc_reg_handler(ds_cb_arg_t, ds_ver_t *, ds_svc_hdl_t);
701ae08745Sheppo static void vc_unreg_handler(ds_cb_arg_t);
711ae08745Sheppo static void vc_data_handler(ds_cb_arg_t, void *, size_t);
721ae08745Sheppo 
731ae08745Sheppo static ds_clnt_ops_t vc_primary_ops = {
741ae08745Sheppo 	vc_reg_handler,		/* ds_primary_reg_cb */
751ae08745Sheppo 	vc_unreg_handler,	/* ds_primary_unreg_cb */
761ae08745Sheppo 	vc_data_handler,	/* ds_data_cb */
771ae08745Sheppo 	&ds_primary_handle	/* cb_arg */
781ae08745Sheppo };
791ae08745Sheppo 
801ae08745Sheppo static ds_clnt_ops_t vc_backup_ops = {
811ae08745Sheppo 	vc_reg_handler,		/* ds_backup_reg_cb */
821ae08745Sheppo 	vc_unreg_handler,	/* ds_backup_unreg_cb */
831ae08745Sheppo 	vc_data_handler,	/* ds_data_cb */
841ae08745Sheppo 	&ds_backup_handle	/* cb_arg */
851ae08745Sheppo };
861ae08745Sheppo 
871ae08745Sheppo static void
vc_reg_handler(ds_cb_arg_t arg,ds_ver_t * ver,ds_svc_hdl_t hdl)881ae08745Sheppo vc_reg_handler(ds_cb_arg_t arg, ds_ver_t *ver, ds_svc_hdl_t hdl)
891ae08745Sheppo {
901ae08745Sheppo 	_NOTE(ARGUNUSED(ver))
911ae08745Sheppo 
921ae08745Sheppo 	if ((ds_svc_hdl_t *)arg == &ds_primary_handle)
931ae08745Sheppo 		ds_primary_handle = hdl;
941ae08745Sheppo 	else if ((ds_svc_hdl_t *)arg == &ds_backup_handle)
95d1a9c4c1Sjm 		ds_backup_handle = hdl;
961ae08745Sheppo }
971ae08745Sheppo 
981ae08745Sheppo static void
vc_unreg_handler(ds_cb_arg_t arg)991ae08745Sheppo vc_unreg_handler(ds_cb_arg_t arg)
1001ae08745Sheppo {
1011ae08745Sheppo 	if ((ds_svc_hdl_t *)arg == &ds_primary_handle)
1021ae08745Sheppo 		ds_primary_handle = DS_INVALID_HDL;
1031ae08745Sheppo 	else if ((ds_svc_hdl_t *)arg == &ds_backup_handle)
1041ae08745Sheppo 		ds_backup_handle = DS_INVALID_HDL;
1051ae08745Sheppo }
1061ae08745Sheppo 
1071ae08745Sheppo static void
vc_data_handler(ds_cb_arg_t arg,void * buf,size_t buflen)1081ae08745Sheppo vc_data_handler(ds_cb_arg_t arg, void *buf, size_t buflen)
1091ae08745Sheppo {
1101ae08745Sheppo 	_NOTE(ARGUNUSED(arg))
1111ae08745Sheppo 
1121ae08745Sheppo 	bcopy(buf, &promif_ds_resp, buflen);
1131ae08745Sheppo 	mutex_enter(&promif_prop_lock);
1141ae08745Sheppo 	cv_signal(&promif_prop_cv);
1151ae08745Sheppo 	mutex_exit(&promif_prop_lock);
1161ae08745Sheppo }
1171ae08745Sheppo 
1181ae08745Sheppo /*
1191ae08745Sheppo  * Initialize the linkage with DS (Domain Services).  We assume that
1201ae08745Sheppo  * the DS module has already been loaded by the platmod.
1211ae08745Sheppo  *
1221ae08745Sheppo  * The call to the DS init functions will eventually result in the
1231ae08745Sheppo  * invocation of our registration callback handlers, at which time DS
1241ae08745Sheppo  * is able to accept requests.
1251ae08745Sheppo  */
1261ae08745Sheppo static void
promif_ds_init(void)1271ae08745Sheppo promif_ds_init(void)
1281ae08745Sheppo {
1291ae08745Sheppo 	static char *me = "promif_ds_init";
1301ae08745Sheppo 	int rv;
1311ae08745Sheppo 
1321ae08745Sheppo 	if ((ds_init =
1331ae08745Sheppo 	    (int (*)())modgetsymvalue("ds_cap_init", 0)) == 0) {
1341ae08745Sheppo 		cmn_err(CE_WARN, "%s: can't find ds_cap_init", me);
1351ae08745Sheppo 		return;
1361ae08745Sheppo 	}
1371ae08745Sheppo 
1381ae08745Sheppo 	if ((ds_send =
1391ae08745Sheppo 	    (int (*)())modgetsymvalue("ds_cap_send", 0)) == 0) {
1401ae08745Sheppo 		cmn_err(CE_WARN, "%s: can't find ds_cap_send", me);
1411ae08745Sheppo 		return;
1421ae08745Sheppo 	}
1431ae08745Sheppo 
1441ae08745Sheppo 	if ((rv = (*ds_init)(&vc_primary_cap, &vc_primary_ops)) != 0) {
1451ae08745Sheppo 		cmn_err(CE_NOTE,
1461ae08745Sheppo 		    "%s: ds_cap_init failed (primary): %d", me, rv);
1471ae08745Sheppo 	}
1481ae08745Sheppo 
1491ae08745Sheppo 
1501ae08745Sheppo 	if ((rv = (*ds_init)(&vc_backup_cap, &vc_backup_ops)) != 0) {
1511ae08745Sheppo 		cmn_err(CE_NOTE,
1521ae08745Sheppo 		    "%s: ds_cap_init failed (backup): %d", me, rv);
1531ae08745Sheppo 	}
1541ae08745Sheppo }
1551ae08745Sheppo 
1561ae08745Sheppo /*
1571ae08745Sheppo  * Prepare for ldom variable requests.
1581ae08745Sheppo  */
1591ae08745Sheppo void
promif_prop_init(void)1601ae08745Sheppo promif_prop_init(void)
1611ae08745Sheppo {
1621ae08745Sheppo 	mutex_init(&promif_prop_lock, NULL, MUTEX_DEFAULT, NULL);
1631ae08745Sheppo 	cv_init(&promif_prop_cv, NULL, CV_DEFAULT, NULL);
1641ae08745Sheppo 
1651ae08745Sheppo 	promif_ds_init();
1661ae08745Sheppo }
1671ae08745Sheppo 
1681ae08745Sheppo 
1691ae08745Sheppo /*
1701ae08745Sheppo  * Replace the current value of a property string given its name and
1711ae08745Sheppo  * new value.
1721ae08745Sheppo  */
1731ae08745Sheppo int
promif_ldom_setprop(char * name,void * value,int valuelen)1741ae08745Sheppo promif_ldom_setprop(char *name, void *value, int valuelen)
1751ae08745Sheppo {
1761ae08745Sheppo 	var_config_msg_t *req;
1771ae08745Sheppo 	var_config_set_req_t *setp;
1781ae08745Sheppo 	var_config_cmd_t cmd;
1791ae08745Sheppo 	ds_svc_hdl_t ds_handle;
1801ae08745Sheppo 	int rv;
1811ae08745Sheppo 	int namelen = strlen(name);
1821ae08745Sheppo 	int paylen = namelen + 1 + valuelen; /* valuelen includes the null */
1831ae08745Sheppo 	static char *me = "promif_ldom_setprop";
1841ae08745Sheppo 
1851ae08745Sheppo 	if (ds_primary_handle != DS_INVALID_HDL)
1861ae08745Sheppo 		ds_handle = ds_primary_handle;
1871ae08745Sheppo 	else if (ds_backup_handle != DS_INVALID_HDL)
1881ae08745Sheppo 		ds_handle = ds_backup_handle;
1891ae08745Sheppo 	else
1901ae08745Sheppo 		return (-1);
1911ae08745Sheppo 
192c8fcc830Sjm 	/*
193c8fcc830Sjm 	 * Since we are emulating OBP, we must comply with the promif
194c8fcc830Sjm 	 * infrastructure and execute only on the originating cpu.
195c8fcc830Sjm 	 */
196de81a4f4Sjm 	thread_affinity_set(curthread, CPU->cpu_id);
197c8fcc830Sjm 
1981ae08745Sheppo 	req = kmem_zalloc(sizeof (var_config_hdr_t) + paylen, KM_SLEEP);
1991ae08745Sheppo 	req->var_config_cmd = VAR_CONFIG_SET_REQ;
2001ae08745Sheppo 	setp = &req->var_config_set;
2011ae08745Sheppo 	(void) strcpy(setp->name_and_value, name);
2021ae08745Sheppo 	(void) strncpy(&setp->name_and_value[namelen + 1], value, valuelen);
2031ae08745Sheppo 
2041ae08745Sheppo 	if ((rv = (*ds_send)(ds_handle, req,
2051ae08745Sheppo 	    sizeof (var_config_hdr_t) + paylen)) != 0) {
2061ae08745Sheppo 		cmn_err(CE_WARN, "%s: ds_cap_send failed: %d", me, rv);
2071ae08745Sheppo 		kmem_free(req, sizeof (var_config_hdr_t) + paylen);
208c8fcc830Sjm 		thread_affinity_clear(curthread);
2091ae08745Sheppo 		return (-1);
2101ae08745Sheppo 	}
2111ae08745Sheppo 
2121ae08745Sheppo 	kmem_free(req, sizeof (var_config_hdr_t) + paylen);
2131ae08745Sheppo 
2141ae08745Sheppo 	mutex_enter(&promif_prop_lock);
215*d3d50737SRafael Vanoni 	if (cv_reltimedwait(&promif_prop_cv, &promif_prop_lock,
216*d3d50737SRafael Vanoni 	    PROMIF_DS_TIMEOUT_SEC * hz, TR_CLOCK_TICK) == -1) {
2171ae08745Sheppo 		cmn_err(CE_WARN, "%s: ds response timeout", me);
2181ae08745Sheppo 		rv = -1;
2191ae08745Sheppo 		goto out;
2201ae08745Sheppo 	}
2211ae08745Sheppo 
2221ae08745Sheppo 	cmd = promif_ds_resp.vc_hdr.cmd;
2231ae08745Sheppo 	if (cmd != VAR_CONFIG_SET_RESP) {
2241ae08745Sheppo 		cmn_err(CE_WARN, "%s: bad response type: %d", me, cmd);
2251ae08745Sheppo 		rv = -1;
2261ae08745Sheppo 		goto out;
2271ae08745Sheppo 	}
2281ae08745Sheppo 	rv = (cfg_rsp->result == VAR_CONFIG_SUCCESS) ? valuelen : -1;
2291ae08745Sheppo 
2301ae08745Sheppo out:
2311ae08745Sheppo 	mutex_exit(&promif_prop_lock);
2321ae08745Sheppo 	thread_affinity_clear(curthread);
2331ae08745Sheppo 	return (rv);
2341ae08745Sheppo }
2351ae08745Sheppo 
2361ae08745Sheppo int
promif_setprop(void * p)2371ae08745Sheppo promif_setprop(void *p)
2381ae08745Sheppo {
2391ae08745Sheppo 	cell_t	*ci = (cell_t *)p;
2401ae08745Sheppo 	pnode_t node;
2411ae08745Sheppo 	caddr_t	name;
2421ae08745Sheppo 	caddr_t	value;
2431ae08745Sheppo 	int	len;
2441ae08745Sheppo 
2451ae08745Sheppo 	ASSERT(ci[1] == 4);
2461ae08745Sheppo 
2471ae08745Sheppo 	node  = p1275_cell2dnode(ci[3]);
2481ae08745Sheppo 	ASSERT(node == prom_optionsnode());
2491ae08745Sheppo 	name  = p1275_cell2ptr(ci[4]);
2501ae08745Sheppo 	value = p1275_cell2ptr(ci[5]);
2511ae08745Sheppo 	len = p1275_cell2int(ci[6]);
2521ae08745Sheppo 
2531ae08745Sheppo 	if (promif_stree_getproplen(node, name) != -1)
2541ae08745Sheppo 		len = promif_ldom_setprop(name, value, len);
2551ae08745Sheppo 
2561ae08745Sheppo 	if (len >= 0)
2571ae08745Sheppo 		len = promif_stree_setprop(node, name, (void *)value, len);
2581ae08745Sheppo 
2591ae08745Sheppo 
2601ae08745Sheppo 	ci[7] = p1275_int2cell(len);
2611ae08745Sheppo 
2621ae08745Sheppo 	return ((len == -1) ? len : 0);
2631ae08745Sheppo }
2641ae08745Sheppo 
2651ae08745Sheppo #endif
2661ae08745Sheppo 
2671ae08745Sheppo int
promif_getprop(void * p)2681ae08745Sheppo promif_getprop(void *p)
2691ae08745Sheppo {
2701ae08745Sheppo 	cell_t	*ci = (cell_t *)p;
2711ae08745Sheppo 	pnode_t	node;
2721ae08745Sheppo 	caddr_t	name;
2731ae08745Sheppo 	caddr_t	value;
2741ae08745Sheppo 	int	len;
2751ae08745Sheppo 
2761ae08745Sheppo 	ASSERT(ci[1] == 4);
2771ae08745Sheppo 
2781ae08745Sheppo 	node  = p1275_cell2dnode(ci[3]);
2791ae08745Sheppo 	name  = p1275_cell2ptr(ci[4]);
2801ae08745Sheppo 	value = p1275_cell2ptr(ci[5]);
2811ae08745Sheppo 
2821ae08745Sheppo 	len = promif_stree_getprop(node, name, value);
2831ae08745Sheppo 
2841ae08745Sheppo 	ci[7] = p1275_int2cell(len);
2851ae08745Sheppo 
2861ae08745Sheppo 	return ((len == -1) ? len : 0);
2871ae08745Sheppo }
2881ae08745Sheppo 
2891ae08745Sheppo int
promif_getproplen(void * p)2901ae08745Sheppo promif_getproplen(void *p)
2911ae08745Sheppo {
2921ae08745Sheppo 	cell_t	*ci = (cell_t *)p;
2931ae08745Sheppo 	pnode_t	node;
2941ae08745Sheppo 	caddr_t	name;
2951ae08745Sheppo 	int	len;
2961ae08745Sheppo 
2971ae08745Sheppo 	ASSERT(ci[1] == 2);
2981ae08745Sheppo 
2991ae08745Sheppo 	node = p1275_cell2dnode(ci[3]);
3001ae08745Sheppo 	name = p1275_cell2ptr(ci[4]);
3011ae08745Sheppo 
3021ae08745Sheppo 	len = promif_stree_getproplen(node, name);
3031ae08745Sheppo 
3041ae08745Sheppo 	ci[5] = p1275_int2cell(len);
3051ae08745Sheppo 
3061ae08745Sheppo 	return (0);
3071ae08745Sheppo }
3081ae08745Sheppo 
3091ae08745Sheppo int
promif_nextprop(void * p)3101ae08745Sheppo promif_nextprop(void *p)
3111ae08745Sheppo {
3121ae08745Sheppo 	cell_t	*ci = (cell_t *)p;
3131ae08745Sheppo 	pnode_t	node;
3141ae08745Sheppo 	caddr_t	prev;
3151ae08745Sheppo 	caddr_t	next;
3161ae08745Sheppo 
3171ae08745Sheppo 	ASSERT(ci[1] == 3);
3181ae08745Sheppo 
3191ae08745Sheppo 	node = p1275_cell2dnode(ci[3]);
3201ae08745Sheppo 	prev = p1275_cell2ptr(ci[4]);
3211ae08745Sheppo 	next = p1275_cell2ptr(ci[5]);
3221ae08745Sheppo 
3231ae08745Sheppo 	(void) promif_stree_nextprop(node, prev, next);
3241ae08745Sheppo 
3251ae08745Sheppo 	return (0);
3261ae08745Sheppo }
327