Home | History | Annotate | Download | only in promif
      1 /*
      2  * CDDL HEADER START
      3  *
      4  * The contents of this file are subject to the terms of the
      5  * Common Development and Distribution License (the "License").
      6  * You may not use this file except in compliance with the License.
      7  *
      8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
      9  * or http://www.opensolaris.org/os/licensing.
     10  * See the License for the specific language governing permissions
     11  * and limitations under the License.
     12  *
     13  * When distributing Covered Code, include this CDDL HEADER in each
     14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
     15  * If applicable, add the following below this CDDL HEADER, with the
     16  * fields enclosed by brackets "[]" replaced with your own identifying
     17  * information: Portions Copyright [yyyy] [name of copyright owner]
     18  *
     19  * CDDL HEADER END
     20  */
     21 
     22 /*
     23  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
     24  * Use is subject to license terms.
     25  */
     26 
     27 #include <sys/types.h>
     28 #include <sys/ddi.h>
     29 #include <sys/sunddi.h>
     30 #include <sys/promif_impl.h>
     31 #include <sys/ds.h>
     32 #include <sys/modctl.h>
     33 #include <sys/ksynch.h>
     34 #include <sys/varconfig.h>
     35 
     36 #ifndef _KMDB
     37 
     38 #define	PROMIF_DS_TIMEOUT_SEC 15
     39 
     40 static kmutex_t promif_prop_lock;
     41 static kcondvar_t promif_prop_cv;
     42 static var_config_msg_t promif_ds_resp;
     43 static var_config_resp_t *cfg_rsp = &promif_ds_resp.var_config_resp;
     44 static int (*ds_send)();
     45 static int (*ds_init)();
     46 
     47 /*
     48  * Domains Services interaction
     49  */
     50 static ds_svc_hdl_t	ds_primary_handle;
     51 static ds_svc_hdl_t	ds_backup_handle;
     52 
     53 static ds_ver_t		vc_version[] = { { 1, 0 } };
     54 
     55 #define	VC_NVERS	(sizeof (vc_version) / sizeof (vc_version[0]))
     56 
     57 static ds_capability_t vc_primary_cap = {
     58 	"var-config",		/* svc_id */
     59 	vc_version,		/* vers */
     60 	VC_NVERS		/* nvers */
     61 };
     62 
     63 static ds_capability_t vc_backup_cap = {
     64 	"var-config-backup",	/* svc_id */
     65 	vc_version,		/* vers */
     66 	VC_NVERS		/* nvers */
     67 };
     68 
     69 static void vc_reg_handler(ds_cb_arg_t, ds_ver_t *, ds_svc_hdl_t);
     70 static void vc_unreg_handler(ds_cb_arg_t);
     71 static void vc_data_handler(ds_cb_arg_t, void *, size_t);
     72 
     73 static ds_clnt_ops_t vc_primary_ops = {
     74 	vc_reg_handler,		/* ds_primary_reg_cb */
     75 	vc_unreg_handler,	/* ds_primary_unreg_cb */
     76 	vc_data_handler,	/* ds_data_cb */
     77 	&ds_primary_handle	/* cb_arg */
     78 };
     79 
     80 static ds_clnt_ops_t vc_backup_ops = {
     81 	vc_reg_handler,		/* ds_backup_reg_cb */
     82 	vc_unreg_handler,	/* ds_backup_unreg_cb */
     83 	vc_data_handler,	/* ds_data_cb */
     84 	&ds_backup_handle	/* cb_arg */
     85 };
     86 
     87 static void
     88 vc_reg_handler(ds_cb_arg_t arg, ds_ver_t *ver, ds_svc_hdl_t hdl)
     89 {
     90 	_NOTE(ARGUNUSED(ver))
     91 
     92 	if ((ds_svc_hdl_t *)arg == &ds_primary_handle)
     93 		ds_primary_handle = hdl;
     94 	else if ((ds_svc_hdl_t *)arg == &ds_backup_handle)
     95 		ds_backup_handle = hdl;
     96 }
     97 
     98 static void
     99 vc_unreg_handler(ds_cb_arg_t arg)
    100 {
    101 	if ((ds_svc_hdl_t *)arg == &ds_primary_handle)
    102 		ds_primary_handle = DS_INVALID_HDL;
    103 	else if ((ds_svc_hdl_t *)arg == &ds_backup_handle)
    104 		ds_backup_handle = DS_INVALID_HDL;
    105 }
    106 
    107 static void
    108 vc_data_handler(ds_cb_arg_t arg, void *buf, size_t buflen)
    109 {
    110 	_NOTE(ARGUNUSED(arg))
    111 
    112 	bcopy(buf, &promif_ds_resp, buflen);
    113 	mutex_enter(&promif_prop_lock);
    114 	cv_signal(&promif_prop_cv);
    115 	mutex_exit(&promif_prop_lock);
    116 }
    117 
    118 /*
    119  * Initialize the linkage with DS (Domain Services).  We assume that
    120  * the DS module has already been loaded by the platmod.
    121  *
    122  * The call to the DS init functions will eventually result in the
    123  * invocation of our registration callback handlers, at which time DS
    124  * is able to accept requests.
    125  */
    126 static void
    127 promif_ds_init(void)
    128 {
    129 	static char *me = "promif_ds_init";
    130 	int rv;
    131 
    132 	if ((ds_init =
    133 	    (int (*)())modgetsymvalue("ds_cap_init", 0)) == 0) {
    134 		cmn_err(CE_WARN, "%s: can't find ds_cap_init", me);
    135 		return;
    136 	}
    137 
    138 	if ((ds_send =
    139 	    (int (*)())modgetsymvalue("ds_cap_send", 0)) == 0) {
    140 		cmn_err(CE_WARN, "%s: can't find ds_cap_send", me);
    141 		return;
    142 	}
    143 
    144 	if ((rv = (*ds_init)(&vc_primary_cap, &vc_primary_ops)) != 0) {
    145 		cmn_err(CE_NOTE,
    146 		    "%s: ds_cap_init failed (primary): %d", me, rv);
    147 	}
    148 
    149 
    150 	if ((rv = (*ds_init)(&vc_backup_cap, &vc_backup_ops)) != 0) {
    151 		cmn_err(CE_NOTE,
    152 		    "%s: ds_cap_init failed (backup): %d", me, rv);
    153 	}
    154 }
    155 
    156 /*
    157  * Prepare for ldom variable requests.
    158  */
    159 void
    160 promif_prop_init(void)
    161 {
    162 	mutex_init(&promif_prop_lock, NULL, MUTEX_DEFAULT, NULL);
    163 	cv_init(&promif_prop_cv, NULL, CV_DEFAULT, NULL);
    164 
    165 	promif_ds_init();
    166 }
    167 
    168 
    169 /*
    170  * Replace the current value of a property string given its name and
    171  * new value.
    172  */
    173 int
    174 promif_ldom_setprop(char *name, void *value, int valuelen)
    175 {
    176 	var_config_msg_t *req;
    177 	var_config_set_req_t *setp;
    178 	var_config_cmd_t cmd;
    179 	ds_svc_hdl_t ds_handle;
    180 	int rv;
    181 	int namelen = strlen(name);
    182 	int paylen = namelen + 1 + valuelen; /* valuelen includes the null */
    183 	static char *me = "promif_ldom_setprop";
    184 
    185 	if (ds_primary_handle != DS_INVALID_HDL)
    186 		ds_handle = ds_primary_handle;
    187 	else if (ds_backup_handle != DS_INVALID_HDL)
    188 		ds_handle = ds_backup_handle;
    189 	else
    190 		return (-1);
    191 
    192 	/*
    193 	 * Since we are emulating OBP, we must comply with the promif
    194 	 * infrastructure and execute only on the originating cpu.
    195 	 */
    196 	thread_affinity_set(curthread, CPU->cpu_id);
    197 
    198 	req = kmem_zalloc(sizeof (var_config_hdr_t) + paylen, KM_SLEEP);
    199 	req->var_config_cmd = VAR_CONFIG_SET_REQ;
    200 	setp = &req->var_config_set;
    201 	(void) strcpy(setp->name_and_value, name);
    202 	(void) strncpy(&setp->name_and_value[namelen + 1], value, valuelen);
    203 
    204 	if ((rv = (*ds_send)(ds_handle, req,
    205 	    sizeof (var_config_hdr_t) + paylen)) != 0) {
    206 		cmn_err(CE_WARN, "%s: ds_cap_send failed: %d", me, rv);
    207 		kmem_free(req, sizeof (var_config_hdr_t) + paylen);
    208 		thread_affinity_clear(curthread);
    209 		return (-1);
    210 	}
    211 
    212 	kmem_free(req, sizeof (var_config_hdr_t) + paylen);
    213 
    214 	mutex_enter(&promif_prop_lock);
    215 	if (cv_reltimedwait(&promif_prop_cv, &promif_prop_lock,
    216 	    PROMIF_DS_TIMEOUT_SEC * hz, TR_CLOCK_TICK) == -1) {
    217 		cmn_err(CE_WARN, "%s: ds response timeout", me);
    218 		rv = -1;
    219 		goto out;
    220 	}
    221 
    222 	cmd = promif_ds_resp.vc_hdr.cmd;
    223 	if (cmd != VAR_CONFIG_SET_RESP) {
    224 		cmn_err(CE_WARN, "%s: bad response type: %d", me, cmd);
    225 		rv = -1;
    226 		goto out;
    227 	}
    228 	rv = (cfg_rsp->result == VAR_CONFIG_SUCCESS) ? valuelen : -1;
    229 
    230 out:
    231 	mutex_exit(&promif_prop_lock);
    232 	thread_affinity_clear(curthread);
    233 	return (rv);
    234 }
    235 
    236 int
    237 promif_setprop(void *p)
    238 {
    239 	cell_t	*ci = (cell_t *)p;
    240 	pnode_t node;
    241 	caddr_t	name;
    242 	caddr_t	value;
    243 	int	len;
    244 
    245 	ASSERT(ci[1] == 4);
    246 
    247 	node  = p1275_cell2dnode(ci[3]);
    248 	ASSERT(node == prom_optionsnode());
    249 	name  = p1275_cell2ptr(ci[4]);
    250 	value = p1275_cell2ptr(ci[5]);
    251 	len = p1275_cell2int(ci[6]);
    252 
    253 	if (promif_stree_getproplen(node, name) != -1)
    254 		len = promif_ldom_setprop(name, value, len);
    255 
    256 	if (len >= 0)
    257 		len = promif_stree_setprop(node, name, (void *)value, len);
    258 
    259 
    260 	ci[7] = p1275_int2cell(len);
    261 
    262 	return ((len == -1) ? len : 0);
    263 }
    264 
    265 #endif
    266 
    267 int
    268 promif_getprop(void *p)
    269 {
    270 	cell_t	*ci = (cell_t *)p;
    271 	pnode_t	node;
    272 	caddr_t	name;
    273 	caddr_t	value;
    274 	int	len;
    275 
    276 	ASSERT(ci[1] == 4);
    277 
    278 	node  = p1275_cell2dnode(ci[3]);
    279 	name  = p1275_cell2ptr(ci[4]);
    280 	value = p1275_cell2ptr(ci[5]);
    281 
    282 	len = promif_stree_getprop(node, name, value);
    283 
    284 	ci[7] = p1275_int2cell(len);
    285 
    286 	return ((len == -1) ? len : 0);
    287 }
    288 
    289 int
    290 promif_getproplen(void *p)
    291 {
    292 	cell_t	*ci = (cell_t *)p;
    293 	pnode_t	node;
    294 	caddr_t	name;
    295 	int	len;
    296 
    297 	ASSERT(ci[1] == 2);
    298 
    299 	node = p1275_cell2dnode(ci[3]);
    300 	name = p1275_cell2ptr(ci[4]);
    301 
    302 	len = promif_stree_getproplen(node, name);
    303 
    304 	ci[5] = p1275_int2cell(len);
    305 
    306 	return (0);
    307 }
    308 
    309 int
    310 promif_nextprop(void *p)
    311 {
    312 	cell_t	*ci = (cell_t *)p;
    313 	pnode_t	node;
    314 	caddr_t	prev;
    315 	caddr_t	next;
    316 
    317 	ASSERT(ci[1] == 3);
    318 
    319 	node = p1275_cell2dnode(ci[3]);
    320 	prev = p1275_cell2ptr(ci[4]);
    321 	next = p1275_cell2ptr(ci[5]);
    322 
    323 	(void) promif_stree_nextprop(node, prev, next);
    324 
    325 	return (0);
    326 }
    327