2N/A/*
2N/A * CDDL HEADER START
2N/A *
2N/A * The contents of this file are subject to the terms of the
2N/A * Common Development and Distribution License (the "License").
2N/A * You may not use this file except in compliance with the License.
2N/A *
2N/A * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
2N/A * or http://www.opensolaris.org/os/licensing.
2N/A * See the License for the specific language governing permissions
2N/A * and limitations under the License.
2N/A *
2N/A * When distributing Covered Code, include this CDDL HEADER in each
2N/A * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
2N/A * If applicable, add the following below this CDDL HEADER, with the
2N/A * fields enclosed by brackets "[]" replaced with your own identifying
2N/A * information: Portions Copyright [yyyy] [name of copyright owner]
2N/A *
2N/A * CDDL HEADER END
2N/A */
2N/A
2N/A/*
2N/A * Copyright (c) 2011, 2012, Oracle and/or its affiliates. All rights reserved.
2N/A */
2N/A
2N/A/*
2N/A * Implement Operations for Active Power Management Properties
2N/A */
2N/A
2N/A#include <sys/types.h>
2N/A#include <stdio.h>
2N/A#include <sys/pm.h>
2N/A#include <errno.h>
2N/A#include <stdlib.h>
2N/A#include <stdint.h>
2N/A#include <string.h>
2N/A#include <strings.h>
2N/A#include <libnvpair.h>
2N/A#include <libscf.h>
2N/A#include <libscf_priv.h>
2N/A#include <libpower.h>
2N/A#include <libpower_impl.h>
2N/A
2N/Atypedef pm_error_t (*pm_smf_validate_f)(scf_simple_prop_t *, const char *,
2N/A void **);
2N/A
2N/Astruct pm_smf_validate_s {
2N/A const char *v_name;
2N/A pm_smf_validate_f v_func;
2N/A};
2N/Atypedef struct pm_smf_validate_s pm_smf_validate_t;
2N/A
2N/Astatic const char *exclude_props[] = {
2N/A PM_PROP_VALUE_AUTH,
2N/A NULL
2N/A};
2N/A
2N/A
2N/Astatic void *pm_smf_tonvpair(scf_simple_prop_t *, data_type_t *, uint_t *);
2N/Astatic pm_error_t pm_smf_write(const char *, const char *, scf_propvec_t *);
2N/A
2N/A/* Property value validation routines for use by setprop */
2N/Astatic pm_error_t pm_smf_validate(scf_simple_prop_t *, const char *,
2N/A void **);
2N/Astatic pm_error_t pm_smf_validate_authority(scf_simple_prop_t *,
2N/A const char *, void **);
2N/Astatic pm_error_t pm_smf_validate_boolean(scf_simple_prop_t *,
2N/A const char *, void **);
2N/Astatic pm_error_t pm_smf_validate_integer(scf_simple_prop_t *,
2N/A const char *, void **);
2N/A
2N/Astatic const pm_smf_validate_t validate_authority = {
2N/A PM_PROP_AUTHORITY, pm_smf_validate_authority};
2N/Astatic const pm_smf_validate_t validate_suspend_enable = {
2N/A PM_PROP_SUSPEND_ENABLE, pm_smf_validate_boolean};
2N/Astatic const pm_smf_validate_t validate_ttfc = {
2N/A PM_PROP_TTFC, pm_smf_validate_integer};
2N/Astatic const pm_smf_validate_t validate_ttmr = {
2N/A PM_PROP_TTMR, pm_smf_validate_integer};
2N/Astatic const pm_smf_validate_t *pm_smf_validators[] = {
2N/A &validate_authority,
2N/A &validate_suspend_enable,
2N/A &validate_ttfc,
2N/A &validate_ttmr,
2N/A NULL
2N/A};
2N/A
2N/A
2N/Apm_error_t
2N/Apm_smf_listprop(nvlist_t **result, const char *instance)
2N/A{
2N/A pm_error_t err;
2N/A uint_t propc;
2N/A const char **pp;
2N/A const char *propname;
2N/A const char *pgname;
2N/A scf_simple_prop_t *prop;
2N/A scf_simple_app_props_t *props;
2N/A data_type_t proptype;
2N/A void *propval;
2N/A
2N/A props = scf_simple_app_props_get(NULL, instance);
2N/A if (props == NULL) {
2N/A /*
2N/A * An error occurred in the SMF layer. Return that information
2N/A * to the caller for processing.
2N/A */
2N/A uu_dprintf(pm_log, UU_DPRINTF_DEBUG, "%s SCF error %d (%s)\n",
2N/A __FUNCTION__, scf_error(), scf_strerror(scf_error()));
2N/A
2N/A return (PM_ERROR_SCF);
2N/A }
2N/A
2N/A err = PM_SUCCESS;
2N/A prop = (scf_simple_prop_t *)scf_simple_app_props_next(props, NULL);
2N/A while (err == PM_SUCCESS && prop != NULL) {
2N/A propname = scf_simple_prop_name(prop);
2N/A pgname = scf_simple_prop_pgname(prop);
2N/A propval = pm_smf_tonvpair(prop, &proptype, &propc);
2N/A
2N/A /*
2N/A * Some properties that are returned by the libscf simple
2N/A * interface are actually internal to the SMF implementation.
2N/A * To avoid the user changing their values here, where it is
2N/A * inappropriate, those properties are specifically excluded
2N/A * from the result set.
2N/A */
2N/A for (pp = exclude_props; *pp != NULL; pp++) {
2N/A if (strncmp(propname, *pp, strlen(*pp)) == 0) {
2N/A break;
2N/A }
2N/A }
2N/A if (*pp == NULL) {
2N/A /* Add the value, if any, to the result list */
2N/A err = pm_result_add(result, PM_AUTHORITY_SMF,
2N/A pgname, propname, proptype, propval, propc);
2N/A if (err == PM_ERROR_INVALID_ARGUMENT) {
2N/A uu_dprintf(pm_log, UU_DPRINTF_DEBUG,
2N/A "%s property %s has no value. Skipping\n",
2N/A __FUNCTION__, propname);
2N/A
2N/A /* Not having a value is OK */
2N/A errno = 0;
2N/A err = PM_SUCCESS;
2N/A }
2N/A } else {
2N/A uu_dprintf(pm_log, UU_DPRINTF_DEBUG,
2N/A "%s property %s is in the exclude list\n",
2N/A __FUNCTION__, propname);
2N/A }
2N/A if (propval != NULL) {
2N/A switch (proptype) {
2N/A case DATA_TYPE_STRING:
2N/A case DATA_TYPE_STRING_ARRAY: {
2N/A int i;
2N/A char **sap = (char **)propval;
2N/A for (i = 0; i < propc; i++) {
2N/A if (sap[i] != NULL) {
2N/A free(sap[i]);
2N/A }
2N/A }
2N/A free(propval);
2N/A }
2N/A break;
2N/A
2N/A case DATA_TYPE_BOOLEAN:
2N/A case DATA_TYPE_BOOLEAN_ARRAY:
2N/A case DATA_TYPE_UINT64:
2N/A case DATA_TYPE_UINT64_ARRAY:
2N/A default:
2N/A free(propval);
2N/A break;
2N/A
2N/A }
2N/A }
2N/A
2N/A /* Check the next property */
2N/A prop = (scf_simple_prop_t *)scf_simple_app_props_next(props,
2N/A prop);
2N/A }
2N/A scf_simple_app_props_free(props);
2N/A
2N/A return (err);
2N/A}
2N/A
2N/A
2N/Apm_error_t
2N/Apm_smf_setprop(nvpair_t *nvp, const char *instance)
2N/A{
2N/A pm_error_t err;
2N/A char *val;
2N/A char *pgname;
2N/A char *propname;
2N/A
2N/A scf_simple_prop_t *prop;
2N/A scf_simple_prop_t *el;
2N/A scf_simple_app_props_t *props;
2N/A scf_propvec_t propvec[2];
2N/A
2N/A errno = 0;
2N/A
2N/A /* Retrieve all of the SMF properties for property information */
2N/A props = scf_simple_app_props_get(NULL, instance);
2N/A if (props == NULL) {
2N/A /*
2N/A * An error occurred in the SMF layer. Return that information
2N/A * to the caller for processing.
2N/A */
2N/A uu_dprintf(pm_log, UU_DPRINTF_DEBUG, "%s SCF error %d (%s)\n",
2N/A __FUNCTION__, scf_error(), scf_strerror(scf_error()));
2N/A
2N/A return (PM_ERROR_SCF);
2N/A }
2N/A
2N/A /* Extract the property name from the incoming nvpair */
2N/A prop = NULL;
2N/A val = strdup(nvpair_name(nvp));
2N/A propname = pm_parse_propname(val, &pgname);
2N/A
2N/A /*
2N/A * Find the SMF property that matches this property name. Note that
2N/A * the power service uses multiple property groups, but the property
2N/A * namespace is unique (otherwise this would not be valid)
2N/A */
2N/A el = (scf_simple_prop_t *)scf_simple_app_props_next(props, NULL);
2N/A while (el != NULL && prop == NULL) {
2N/A char *np;
2N/A size_t nlen;
2N/A
2N/A np = scf_simple_prop_name(el);
2N/A nlen = strlen(np);
2N/A
2N/A if (strncmp(propname, np, nlen) == 0) {
2N/A prop = el;
2N/A }
2N/A
2N/A /* Check the next property */
2N/A el = (scf_simple_prop_t *)scf_simple_app_props_next(props, el);
2N/A }
2N/A if (prop == NULL) {
2N/A errno = ENOENT;
2N/A uu_dprintf(pm_log, UU_DPRINTF_DEBUG,
2N/A "%s could not find SMF property %s instance %s\n",
2N/A __FUNCTION__, propname, instance);
2N/A free(val);
2N/A
2N/A return (PM_ERROR_PROPERTY_NOT_FOUND);
2N/A }
2N/A free(val);
2N/A
2N/A /* The new value comes in as a string value */
2N/A if (nvpair_value_string(nvp, &val) != 0) {
2N/A errno = EINVAL;
2N/A return (PM_ERROR_MISSING_PROPERTY_VALUE);
2N/A }
2N/A
2N/A /*
2N/A * We now have the property from SCF, which is authoritative.
2N/A * Initialize the property vector using this information
2N/A */
2N/A bzero(&propvec, sizeof (propvec));
2N/A propvec[1].pv_prop = NULL;
2N/A propvec[0].pv_prop = scf_simple_prop_name(prop);
2N/A propvec[0].pv_type = scf_simple_prop_type(prop);
2N/A propvec[0].pv_mval = B_FALSE;
2N/A err = pm_smf_validate(prop, val, &(propvec[0].pv_ptr));
2N/A if (err != PM_SUCCESS) {
2N/A return (err);
2N/A }
2N/A
2N/A /* Write the property vector to SMF */
2N/A err = pm_smf_write(instance, scf_simple_prop_pgname(prop), propvec);
2N/A
2N/A /* Clean up allocated memory and return to the caller */
2N/A if (propvec[0].pv_ptr != NULL) {
2N/A /* The value was allocated by the property validator */
2N/A free(propvec[0].pv_ptr);
2N/A }
2N/A
2N/A return (err);
2N/A}
2N/A
2N/A
2N/Astatic pm_error_t
2N/Apm_smf_write(const char *instance, const char *pgname, scf_propvec_t *propvec)
2N/A{
2N/A int err;
2N/A scf_propvec_t *errprop = NULL;
2N/A
2N/A /* Write the property vector to the SMF database */
2N/A err = scf_write_propvec(instance, pgname, propvec, &errprop);
2N/A if (err != SCF_SUCCESS) {
2N/A uu_dprintf(pm_log, UU_DPRINTF_DEBUG,
2N/A "%s scf_write_propvec prop %s failed %d (%s)\n",
2N/A __FUNCTION__, propvec[0].pv_prop, scf_error(),
2N/A scf_strerror(scf_error()));
2N/A return (PM_ERROR_SCF);
2N/A }
2N/A
2N/A return (PM_SUCCESS);
2N/A}
2N/A
2N/A
2N/Astatic void *
2N/Apm_smf_tonvpair(scf_simple_prop_t *prop, data_type_t *valtype, uint_t *propc)
2N/A{
2N/A int i;
2N/A size_t nval;
2N/A boolean_t *bap;
2N/A char **sap;
2N/A uint64_t *uap;
2N/A void *result;
2N/A char *propname;
2N/A scf_type_t proptype;
2N/A
2N/A nval = *propc = scf_simple_prop_numvalues(prop);
2N/A propname = scf_simple_prop_name(prop);
2N/A if (nval == 0) {
2N/A uu_dprintf(pm_log, UU_DPRINTF_DEBUG,
2N/A "%s property %s has no values\n", __FUNCTION__,
2N/A propname);
2N/A
2N/A return (NULL);
2N/A }
2N/A
2N/A result = NULL;
2N/A proptype = scf_simple_prop_type(prop);
2N/A uu_dprintf(pm_log, UU_DPRINTF_DEBUG,
2N/A "%s property %s type %d number of values %d\n",
2N/A __FUNCTION__, propname, proptype, nval);
2N/A switch (proptype) {
2N/A case SCF_TYPE_BOOLEAN:
2N/A *valtype = (nval == 1 ? DATA_TYPE_BOOLEAN_VALUE :
2N/A DATA_TYPE_BOOLEAN_ARRAY);
2N/A bap = (boolean_t *)calloc(nval, sizeof (boolean_t));
2N/A if (bap != NULL) {
2N/A for (i = 0; i < nval; i++) {
2N/A uint8_t *b;
2N/A b = scf_simple_prop_next_boolean(prop);
2N/A bap[i] = (*b != 0 ? B_TRUE : B_FALSE);
2N/A }
2N/A result = (void *)bap;
2N/A }
2N/A break;
2N/A
2N/A case SCF_TYPE_INTEGER:
2N/A *valtype = (nval == 1 ? DATA_TYPE_UINT64 :
2N/A DATA_TYPE_UINT64_ARRAY);
2N/A uap = (uint64_t *)calloc(nval, sizeof (uint64_t));
2N/A if (uap != NULL) {
2N/A for (i = 0; i < nval; i++) {
2N/A int64_t *val =
2N/A scf_simple_prop_next_integer(prop);
2N/A uap[i] = *val;
2N/A }
2N/A result = (void *)uap;
2N/A }
2N/A break;
2N/A
2N/A case SCF_TYPE_ASTRING:
2N/A *valtype = (*propc == 1 ? DATA_TYPE_STRING :
2N/A DATA_TYPE_STRING_ARRAY);
2N/A sap = (char **)calloc(nval, sizeof (char *));
2N/A if (sap != NULL) {
2N/A for (i = 0; i < nval; i++) {
2N/A char *s;
2N/A s = strdup(scf_simple_prop_next_astring(prop));
2N/A sap[i] = s;
2N/A }
2N/A result = (void *)sap;
2N/A }
2N/A break;
2N/A
2N/A default:
2N/A *valtype = DATA_TYPE_UNKNOWN;
2N/A errno = ENOENT;
2N/A return (NULL);
2N/A break;
2N/A }
2N/A
2N/A return (result);
2N/A}
2N/A
2N/A
2N/Apm_error_t
2N/Apm_smf_add_pgname(nvlist_t *result, const char *instance)
2N/A{
2N/A pm_error_t err;
2N/A char *propname;
2N/A char *pgname;
2N/A nvpair_t *nvp;
2N/A nvlist_t *nvl;
2N/A scf_simple_prop_t *prop;
2N/A scf_simple_app_props_t *props;
2N/A
2N/A /* Retrieve all of the properties from SMF */
2N/A props = scf_simple_app_props_get(NULL, instance);
2N/A if (props == NULL) {
2N/A /*
2N/A * An error occurred in the SMF layer. Return that information
2N/A * to the caller for processing.
2N/A */
2N/A uu_dprintf(pm_log, UU_DPRINTF_DEBUG, "%s SCF error %d (%s)\n",
2N/A __FUNCTION__, scf_error(), scf_strerror(scf_error()));
2N/A
2N/A return (PM_ERROR_SCF);
2N/A }
2N/A
2N/A err = PM_SUCCESS;
2N/A prop = (scf_simple_prop_t *)scf_simple_app_props_next(props, NULL);
2N/A while (err == PM_SUCCESS && prop != NULL) {
2N/A propname = scf_simple_prop_name(prop);
2N/A pgname = scf_simple_prop_pgname(prop);
2N/A
2N/A /* Find the property in the result list */
2N/A nvl = NULL;
2N/A if (nvlist_lookup_nvlist(result, propname, &nvl) == 0 &&
2N/A nvl != NULL) {
2N/A /*
2N/A * The property exists in the result list. Check
2N/A * for a property group name.
2N/A */
2N/A nvp = NULL;
2N/A if (nvlist_lookup_nvpair(nvl, PM_PROP_PGNAME, &nvp)) {
2N/A /*
2N/A * Could not find the property group name for
2N/A * this property. Add it now.
2N/A */
2N/A uu_dprintf(pm_log, UU_DPRINTF_DEBUG,
2N/A "%s adding property group name for "
2N/A "property %s\n", __FUNCTION__, propname);
2N/A
2N/A errno = nvlist_add_string(nvl, PM_PROP_PGNAME,
2N/A pgname);
2N/A if (errno != 0) {
2N/A err = PM_ERROR_NVLIST;
2N/A }
2N/A }
2N/A } else {
2N/A uu_dprintf(pm_log, UU_DPRINTF_DEBUG,
2N/A "%s could not find property %s in result set\n",
2N/A __FUNCTION__, propname);
2N/A }
2N/A
2N/A /* Check the next property */
2N/A prop = (scf_simple_prop_t *)scf_simple_app_props_next(props,
2N/A prop);
2N/A }
2N/A scf_simple_app_props_free(props);
2N/A
2N/A return (err);
2N/A}
2N/A
2N/A
2N/Apm_error_t
2N/Apm_smf_validate(scf_simple_prop_t *prop, const char *val, void **result)
2N/A{
2N/A int err;
2N/A size_t len;
2N/A char *propname;
2N/A const pm_smf_validate_t *ep, **epp;
2N/A
2N/A propname = scf_simple_prop_name(prop);
2N/A len = strlen(propname);
2N/A for (epp = pm_smf_validators; *epp != NULL; epp++) {
2N/A ep = *epp;
2N/A if (strncmp(propname, ep->v_name, len) == 0)
2N/A break;
2N/A }
2N/A if (*epp == NULL) {
2N/A return (PM_ERROR_INVALID_PROPERTY_VALUE);
2N/A }
2N/A ep = *epp;
2N/A
2N/A /* Call the validation routine for this property */
2N/A err = (ep->v_func)(prop, val, result);
2N/A
2N/A return (err);
2N/A}
2N/A
2N/A
2N/Apm_error_t
2N/Apm_smf_validate_authority(scf_simple_prop_t *prop, const char *val,
2N/A void **result)
2N/A{
2N/A pm_authority_t authority;
2N/A
2N/A /* Validate that this property takes a string */
2N/A if (scf_simple_prop_type(prop) != SCF_TYPE_ASTRING) {
2N/A uu_dprintf(pm_log, UU_DPRINTF_DEBUG,
2N/A "%s property %s has unexpected type %d\n", __FUNCTION__,
2N/A scf_simple_prop_name(prop), scf_simple_prop_type(prop));
2N/A return (PM_ERROR_INVALID_AUTHORITY);
2N/A }
2N/A
2N/A /* Validate that the given string is a valid authority */
2N/A authority = pm_authority_get(val);
2N/A if (authority == PM_AUTHORITY_INVALID) {
2N/A return (PM_ERROR_INVALID_AUTHORITY);
2N/A }
2N/A
2N/A /* The authority is valid. Make a copy and return to the caller */
2N/A *result = (void *)strdup(val);
2N/A
2N/A return (PM_SUCCESS);
2N/A}
2N/A
2N/A
2N/Apm_error_t
2N/Apm_smf_validate_boolean(scf_simple_prop_t *prop, const char *val,
2N/A void **result)
2N/A{
2N/A pm_error_t err;
2N/A boolean_t b;
2N/A boolean_t *r;
2N/A
2N/A /* Validate that this property takes a boolean */
2N/A if (scf_simple_prop_type(prop) != SCF_TYPE_BOOLEAN) {
2N/A uu_dprintf(pm_log, UU_DPRINTF_DEBUG,
2N/A "%s property %s has unexpected type %d\n", __FUNCTION__,
2N/A scf_simple_prop_name(prop), scf_simple_prop_type(prop));
2N/A
2N/A return (PM_ERROR_INVALID_BOOLEAN);
2N/A }
2N/A
2N/A /* Validate that the given string is a valid boolean */
2N/A err = pm_parse_boolean(val, &b);
2N/A if (err != PM_SUCCESS) {
2N/A uu_dprintf(pm_log, UU_DPRINTF_DEBUG,
2N/A "%s invalid boolean \"%s\" for property %s\n",
2N/A __FUNCTION__, val, scf_simple_prop_name(prop));
2N/A
2N/A return (PM_ERROR_INVALID_BOOLEAN);
2N/A }
2N/A
2N/A /* The boolean is valid. Make a copy and return to the caller */
2N/A r = malloc(sizeof (boolean_t));
2N/A if (r == NULL) {
2N/A return (PM_ERROR_SYSTEM);
2N/A }
2N/A *r = b;
2N/A *result = r;
2N/A
2N/A return (PM_SUCCESS);
2N/A}
2N/A
2N/A
2N/Apm_error_t
2N/Apm_smf_validate_integer(scf_simple_prop_t *prop, const char *val,
2N/A void **result)
2N/A{
2N/A pm_error_t err;
2N/A int64_t i;
2N/A int64_t *r;
2N/A
2N/A /* Validate that this property takes an integer */
2N/A if (scf_simple_prop_type(prop) != SCF_TYPE_INTEGER) {
2N/A uu_dprintf(pm_log, UU_DPRINTF_DEBUG,
2N/A "%s property %s has unexpected type %d\n", __FUNCTION__,
2N/A scf_simple_prop_name(prop), scf_simple_prop_type(prop));
2N/A
2N/A return (PM_ERROR_INVALID_INTEGER);
2N/A }
2N/A
2N/A /*
2N/A * Validate that the given string is a valid integer for the power
2N/A * service (they are all non-negative)
2N/A */
2N/A err = pm_parse_integer(val, &i);
2N/A if (err != PM_SUCCESS || i < 0) {
2N/A uu_dprintf(pm_log, UU_DPRINTF_DEBUG,
2N/A "%s invalid integer \"%s\" for property %s\n",
2N/A __FUNCTION__, val, scf_simple_prop_name(prop));
2N/A
2N/A return (PM_ERROR_INVALID_INTEGER);
2N/A }
2N/A
2N/A /* The boolean is valid. Make a copy and return to the caller */
2N/A r = malloc(sizeof (int64_t));
2N/A if (r == NULL) {
2N/A return (PM_ERROR_SYSTEM);
2N/A }
2N/A *r = i;
2N/A *result = r;
2N/A
2N/A return (PM_SUCCESS);
2N/A}