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 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) 95d1a9c4c1Sjm22469 ds_backup_handle = hdl; 961ae08745Sheppo } 971ae08745Sheppo 981ae08745Sheppo static void 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 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 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 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 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 192c8fcc830Sjm22469 /* 193c8fcc830Sjm22469 * Since we are emulating OBP, we must comply with the promif 194c8fcc830Sjm22469 * infrastructure and execute only on the originating cpu. 195c8fcc830Sjm22469 */ 196de81a4f4Sjm22469 thread_affinity_set(curthread, CPU->cpu_id); 197c8fcc830Sjm22469 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); 208c8fcc830Sjm22469 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 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 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 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 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