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 2006 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 req = kmem_zalloc(sizeof (var_config_hdr_t) + paylen, KM_SLEEP); 195 req->var_config_cmd = VAR_CONFIG_SET_REQ; 196 setp = &req->var_config_set; 197 (void) strcpy(setp->name_and_value, name); 198 (void) strncpy(&setp->name_and_value[namelen + 1], value, valuelen); 199 200 if ((rv = (*ds_send)(ds_handle, req, 201 sizeof (var_config_hdr_t) + paylen)) != 0) { 202 cmn_err(CE_WARN, "%s: ds_cap_send failed: %d", me, rv); 203 kmem_free(req, sizeof (var_config_hdr_t) + paylen); 204 return (-1); 205 } 206 207 kmem_free(req, sizeof (var_config_hdr_t) + paylen); 208 209 /* 210 * Since we are emulating OBP, we must comply with the promif 211 * infrastructure and execute only on the originating cpu. 212 */ 213 thread_affinity_set(curthread, CPU_CURRENT); 214 215 mutex_enter(&promif_prop_lock); 216 if (cv_timedwait(&promif_prop_cv, 217 &promif_prop_lock, lbolt + PROMIF_DS_TIMEOUT_SEC * hz) == -1) { 218 cmn_err(CE_WARN, "%s: ds response timeout", me); 219 rv = -1; 220 goto out; 221 } 222 223 cmd = promif_ds_resp.vc_hdr.cmd; 224 if (cmd != VAR_CONFIG_SET_RESP) { 225 cmn_err(CE_WARN, "%s: bad response type: %d", me, cmd); 226 rv = -1; 227 goto out; 228 } 229 rv = (cfg_rsp->result == VAR_CONFIG_SUCCESS) ? valuelen : -1; 230 231 out: 232 mutex_exit(&promif_prop_lock); 233 thread_affinity_clear(curthread); 234 return (rv); 235 } 236 237 int 238 promif_setprop(void *p) 239 { 240 cell_t *ci = (cell_t *)p; 241 pnode_t node; 242 caddr_t name; 243 caddr_t value; 244 int len; 245 246 ASSERT(ci[1] == 4); 247 248 node = p1275_cell2dnode(ci[3]); 249 ASSERT(node == prom_optionsnode()); 250 name = p1275_cell2ptr(ci[4]); 251 value = p1275_cell2ptr(ci[5]); 252 len = p1275_cell2int(ci[6]); 253 254 if (promif_stree_getproplen(node, name) != -1) 255 len = promif_ldom_setprop(name, value, len); 256 257 if (len >= 0) 258 len = promif_stree_setprop(node, name, (void *)value, len); 259 260 261 ci[7] = p1275_int2cell(len); 262 263 return ((len == -1) ? len : 0); 264 } 265 266 #endif 267 268 int 269 promif_getprop(void *p) 270 { 271 cell_t *ci = (cell_t *)p; 272 pnode_t node; 273 caddr_t name; 274 caddr_t value; 275 int len; 276 277 ASSERT(ci[1] == 4); 278 279 node = p1275_cell2dnode(ci[3]); 280 name = p1275_cell2ptr(ci[4]); 281 value = p1275_cell2ptr(ci[5]); 282 283 len = promif_stree_getprop(node, name, value); 284 285 ci[7] = p1275_int2cell(len); 286 287 return ((len == -1) ? len : 0); 288 } 289 290 int 291 promif_getproplen(void *p) 292 { 293 cell_t *ci = (cell_t *)p; 294 pnode_t node; 295 caddr_t name; 296 int len; 297 298 ASSERT(ci[1] == 2); 299 300 node = p1275_cell2dnode(ci[3]); 301 name = p1275_cell2ptr(ci[4]); 302 303 len = promif_stree_getproplen(node, name); 304 305 ci[5] = p1275_int2cell(len); 306 307 return (0); 308 } 309 310 int 311 promif_nextprop(void *p) 312 { 313 cell_t *ci = (cell_t *)p; 314 pnode_t node; 315 caddr_t prev; 316 caddr_t next; 317 318 ASSERT(ci[1] == 3); 319 320 node = p1275_cell2dnode(ci[3]); 321 prev = p1275_cell2ptr(ci[4]); 322 next = p1275_cell2ptr(ci[5]); 323 324 (void) promif_stree_nextprop(node, prev, next); 325 326 return (0); 327 } 328