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