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