/* -*- linux-c -*-
*
* (C) Copyright IBM Corp. 2004
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. This
* file and program are licensed under a BSD style license. See
* the Copying file included with the OpenHPI distribution for
* full licensing terms.
*
* Author(s):
* Steve Sherman <stevees@us.ibm.com>
*/
#include <glib.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <SaHpi.h>
#include <oh_utils.h>
#include <oh_error.h>
/**
* oh_decode_eventstate:
* @event_state: Event state bit map to be converted to a string.
* @event_cat: Event category of @event_state.
* @buffer: Pointer to buffer to store generated string.
*
* Converts @event_state into a string based on @event_state's HPI definition.
* For example, @event_state = SAHPI_ES_UPPER_MAJOR | SAHPI_ES_UPPER_MINOR
* is returned as the string "UPPER_MINOR | UPPER_MAJOR".
* String is stored in an SaHpiTextBufferT data structure.
*
* Function validates that the @event_state bit map is valid for @event_cat.
*
* SAHPI_ES_UNSPECIFIED definitions are stripped from @event_state, if there are
* other valid non-global states defined. For example, @event_state =
* SAHPI_ES_IDLE | SAHPI_ES_UNSPECIFIED, returns the string "IDLE".
*
* Returns:
* SA_OK - normal operation.
* SA_ERR_HPI_INVALID_PARAMS - @buffer is NULL; Invalid @event_state or @event_cat.
* SA_ERR_HPI_OUT_OF_SPACE - @buffer too small.
**/
SaErrorT oh_decode_eventstate(SaHpiEventStateT event_state,
SaHpiEventCategoryT event_cat,
SaHpiTextBufferT *buffer)
{
int i, found;
SaErrorT err;
SaHpiTextBufferT working;
/* Don't check for mutual exclusive events, since we want to see them all */
if (!buffer || !oh_valid_eventstate(event_state, event_cat, SAHPI_FALSE)) {
return(SA_ERR_HPI_INVALID_PARAMS);
}
err = oh_init_textbuffer(&working);
if (err != SA_OK) { return(err); }
found = 0;
/* Look for category's event states */
for (i=0; i<OH_MAX_STATE_STRINGS; i++) {
if (state_strings[i].category == event_cat) {
if ((state_strings[i].state & event_state) == state_strings[i].state) {
found++;
err = oh_append_textbuffer(&working, (char *)state_strings[i].str);
if (err != SA_OK) { return(err); }
err = oh_append_textbuffer(&working, OH_ENCODE_DELIMITER);
if (err != SA_OK) { return(err); }
}
}
}
/* Look for global event states */
for (i=0; i<OH_MAX_STATE_GLOBAL_STRINGS; i++) {
if ((state_global_strings[i].state & event_state) == state_global_strings[i].state) {
/* Strip any UNSPECIFIED definitions, if another definition found */
if (!(found && state_global_strings[i].state == SAHPI_ES_UNSPECIFIED)) {
found++;
err = oh_append_textbuffer(&working, (char *)state_global_strings[i].str);
if (err != SA_OK) { return(err); }
err = oh_append_textbuffer(&working, OH_ENCODE_DELIMITER);
if (err != SA_OK) { return(err); }
}
}
}
/* Remove last delimiter */
if (found) {
for (i=0; i<OH_ENCODE_DELIMITER_LENGTH + 1; i++) {
working.Data[working.DataLength - i] = 0x00;
}
working.DataLength = working.DataLength - OH_ENCODE_DELIMITER_LENGTH;
}
err = oh_copy_textbuffer(buffer, &working);
return(SA_OK);
}
/**
* oh_encode_eventstate:
* @buffer: Pointer to buffer containing string representation of event
* state bit map. Generally received from oh_decode_eventstate().
* @event_state: Pointer to store generated event state bit map.
* @event_cat: Pointer to store generated event category.
*
* Converts string representation of an event state bit map (usually generated
* by oh_decode_eventstate() back into an HPI event state and category
* structure. For example, the string "UPPER_MINOR | UPPER_MAJOR" generates
* event state = SAHPI_ES_UPPER_MAJOR | SAHPI_ES_UPPER_MINOR and
* event category = SAHPI_ES_THRESHOLD.
* Function validates that the @event_state bit map is valid for @event_cat. And
* that the states are complete and not mutually exclusive.
*
* NOTE!
* @event_cat cannot always be deterministically calculated.
*
* - if @event_state is SAHPI_ES_UNSPECIFIED, @event_cat will be SAHPI_EC_UNSPECIFIED
* (though any category is valid).
* - For event categories with the same events defined (e.g. SAHPI_EC_GENERIC and
* SAHPI_EC_SENSOR_SPECIFIC), the category returned may be either one.
*
* Returns:
* SA_OK - normal operation.
* SA_ERR_HPI_INVALID_PARAMS - @buffer, @event_state, or @event_cat NULL.
* No Data in @buffer, invalid format, or
* @event_state bit map not valid for @event_cat.
* SA_ERR_HPI_OUT_OF_SPACE - @buffer too small.
**/
SaErrorT oh_encode_eventstate(SaHpiTextBufferT *buffer,
SaHpiEventStateT *event_state,
SaHpiEventCategoryT *event_cat)
{
gchar *gstr = NULL;
gchar **eventdefs = NULL;
int i, j, found_event, found_global_event;
SaErrorT rtncode = SA_OK;
SaHpiEventStateT working_state=0;
SaHpiEventCategoryT working_cat=0;
if (!buffer || !event_state || !event_cat) {
return(SA_ERR_HPI_INVALID_PARAMS);
}
if (buffer->Data == NULL || buffer->Data[0] == '\0') {
return(SA_ERR_HPI_INVALID_PARAMS);
}
if (buffer->DataLength < SAHPI_MAX_TEXT_BUFFER_LENGTH) {
buffer->Data[buffer->DataLength] = '\0';
}
/* Split out event definitions */
if (buffer->DataLength < SAHPI_MAX_TEXT_BUFFER_LENGTH) {
buffer->Data[buffer->DataLength] = '\0';
}
gstr = g_strstrip(g_strndup((gchar *)buffer->Data, SAHPI_MAX_TEXT_BUFFER_LENGTH));
if (gstr == NULL || gstr[0] == '\0') {
CRIT("g_strstrip failed");
rtncode = SA_ERR_HPI_INTERNAL_ERROR;
goto CLEANUP;
}
eventdefs = g_strsplit(gstr, OH_ENCODE_DELIMITER_CHAR, -1);
if (eventdefs == NULL) {
rtncode = SA_ERR_HPI_INVALID_PARAMS;
goto CLEANUP;
}
for (i=0; eventdefs[i] != NULL && eventdefs[i][0] != '\0'; i++) {
eventdefs[i] = g_strstrip(eventdefs[i]);
found_event = found_global_event = 0;
/* Look for category event states */
for (j=0; j<OH_MAX_STATE_STRINGS; j++) {
if (strcasecmp(eventdefs[i], (char *)state_strings[j].str) == 0) {
found_event++;
/* Don't add twice for categories with duplicate events */
if (!(working_state & state_strings[j].state)) {
working_state = working_state + state_strings[j].state;
}
working_cat = state_strings[j].category;
}
}
/* Look for global event states */
for (j=0; j<OH_MAX_STATE_GLOBAL_STRINGS; j++) {
if (strcasecmp(eventdefs[i], (char *)state_global_strings[j].str) == 0) {
found_global_event++;
/* Don't add twice for categories with duplicate events */
if (!(working_state & state_global_strings[j].state)) {
working_state = working_state + state_global_strings[j].state;
}
working_cat = state_global_strings[j].category;
}
}
if (!found_event && !found_global_event) {
CRIT("No events found");
rtncode = SA_ERR_HPI_INVALID_PARAMS;
goto CLEANUP;
}
}
/* Check for mutually exclusive event states */
if (oh_valid_eventstate(working_state, working_cat, SAHPI_TRUE)) {
*event_state = working_state;
*event_cat = working_cat;
}
else {
rtncode = SA_ERR_HPI_INVALID_PARAMS;
}
CLEANUP:
g_free(gstr);
g_strfreev(eventdefs);
return(rtncode);
}
/**
* oh_valid_eventstate:
* @event_state: Event state bit field.
* @event_cat: Event's category.
* @check_mutal_exclusion: Boolean.
*
* Validates that all the events in the event_state bit field are valid
* for the event category. If @check_mutal_exclusion is true, the routine
* also checks for mutually exclusive events and that thresholds events
* have all the appropriate lower-level threshold event states set.
*
* Returns:
* SAHPI_TRUE - Event(s) valid for category and met HPI spec criteria
* for exclusiveness and completeness.
* SAHPI_FALSE - Any event(s) in bit field not valid for category or
* category is invalid.
**/
SaHpiBoolT oh_valid_eventstate(SaHpiEventStateT event_state,
SaHpiEventCategoryT event_cat,
SaHpiBoolT check_mutal_exclusion)
{
SaHpiEventStateT valid_states;
switch(event_cat) {
case SAHPI_EC_UNSPECIFIED:
/* Only SAHPI_ES_UNSPECIFIED valid for this category */
if (event_state) {
CRIT("Invalid event state.");
return(SAHPI_FALSE);
}
return(SAHPI_TRUE);
case SAHPI_EC_THRESHOLD:
valid_states = SAHPI_ES_LOWER_MINOR |
SAHPI_ES_LOWER_MAJOR |
SAHPI_ES_LOWER_CRIT |
SAHPI_ES_UPPER_MINOR |
SAHPI_ES_UPPER_MAJOR |
SAHPI_ES_UPPER_CRIT;
if (event_state & (~valid_states)) {
CRIT("Invalid event state.");
return(SAHPI_FALSE);
}
#if 0
/* Check that all lower-level thresholds are set */
if (check_mutal_exclusion) {
if (event_state & SAHPI_ES_LOWER_CRIT) {
if (!(event_state & SAHPI_ES_LOWER_MAJOR)) {
CRIT("Critical lower threshold event set; but not major");
return(SAHPI_FALSE);
}
}
if (event_state & SAHPI_ES_LOWER_MAJOR) {
if (!(event_state & SAHPI_ES_LOWER_MINOR)) {
CRIT("Major lower threshold event set; but not minor");
return(SAHPI_FALSE);
}
}
if (event_state & SAHPI_ES_UPPER_CRIT) {
if (!(event_state & SAHPI_ES_UPPER_MAJOR)) {
CRIT("Critical upper threshold event set; but not major");
return(SAHPI_FALSE);
}
}
if (event_state & SAHPI_ES_UPPER_MAJOR) {
if (!(event_state & SAHPI_ES_UPPER_MINOR)) {
CRIT("Major upper threshold event set; but not minor");
return(SAHPI_FALSE);
}
}
}
#endif
return(SAHPI_TRUE);
case SAHPI_EC_USAGE:
valid_states = SAHPI_ES_IDLE |
SAHPI_ES_ACTIVE |
SAHPI_ES_BUSY;
if (event_state & (~valid_states)) {
CRIT("Invalid event state.");
return(SAHPI_FALSE);
}
/* ??? Any of these mutually exclusive */
return(SAHPI_TRUE);
case SAHPI_EC_STATE:
valid_states = SAHPI_ES_STATE_DEASSERTED |
SAHPI_ES_STATE_ASSERTED;
if (event_state & (~valid_states)) {
CRIT("Invalid event state.");
return(SAHPI_FALSE);
}
if (check_mutal_exclusion) {
if ((event_state & SAHPI_ES_STATE_DEASSERTED) &&
(event_state & SAHPI_ES_STATE_ASSERTED)) {
CRIT("Mutally exclusive STATE event states defined");
return(SAHPI_FALSE);
}
}
return(SAHPI_TRUE);
case SAHPI_EC_PRED_FAIL:
valid_states = SAHPI_ES_PRED_FAILURE_DEASSERT |
SAHPI_ES_PRED_FAILURE_ASSERT;
if (event_state & (~valid_states)) {
CRIT("Invalid event state.");
return(SAHPI_FALSE);
}
if (check_mutal_exclusion) {
if ((event_state & SAHPI_ES_PRED_FAILURE_DEASSERT) &&
(event_state & SAHPI_ES_PRED_FAILURE_ASSERT)) {
CRIT("Mutally exclusive PRED_FAIL event states defined");
return(SAHPI_FALSE);
}
}
return(SAHPI_TRUE);
case SAHPI_EC_LIMIT:
valid_states = SAHPI_ES_LIMIT_NOT_EXCEEDED |
SAHPI_ES_LIMIT_EXCEEDED;
if (event_state & (~valid_states)) {
CRIT("Invalid event state.");
return(SAHPI_FALSE);
}
if (check_mutal_exclusion) {
if ((event_state & SAHPI_ES_LIMIT_NOT_EXCEEDED) &&
(event_state & SAHPI_ES_LIMIT_EXCEEDED)) {
CRIT("Mutally exclusive LIMIT event states defined");
return(SAHPI_FALSE);
}
}
return(SAHPI_TRUE);
case SAHPI_EC_PERFORMANCE:
valid_states = SAHPI_ES_PERFORMANCE_MET |
SAHPI_ES_PERFORMANCE_LAGS;
if (event_state & (~valid_states)) {
CRIT("Invalid event state.");
return(SAHPI_FALSE);
}
if (check_mutal_exclusion) {
if ((event_state & SAHPI_ES_PERFORMANCE_MET) &&
(event_state & SAHPI_ES_PERFORMANCE_LAGS)) {
CRIT("Mutally exclusive PERFORMANCE event states defined");
return(SAHPI_FALSE);
}
}
return(SAHPI_TRUE);
case SAHPI_EC_SEVERITY:
valid_states = SAHPI_ES_OK |
SAHPI_ES_MINOR_FROM_OK |
SAHPI_ES_MAJOR_FROM_LESS |
SAHPI_ES_CRITICAL_FROM_LESS |
SAHPI_ES_MINOR_FROM_MORE |
SAHPI_ES_MAJOR_FROM_CRITICAL |
SAHPI_ES_CRITICAL |
SAHPI_ES_MONITOR |
SAHPI_ES_INFORMATIONAL;
if (event_state & (~valid_states)) {
CRIT("Invalid event state.");
return(SAHPI_FALSE);
}
/* ?? Any of these exclusive */
return(SAHPI_TRUE);
case SAHPI_EC_PRESENCE:
valid_states = SAHPI_ES_ABSENT |
SAHPI_ES_PRESENT;
if (event_state & (~valid_states)) {
CRIT("Invalid event state.");
return(SAHPI_FALSE);
}
if (check_mutal_exclusion) {
if ((event_state & SAHPI_ES_ABSENT) &&
(event_state & SAHPI_ES_PRESENT)) {
CRIT("Mutally exclusive PRESENCE event states defined");
return(SAHPI_FALSE);
}
}
return(SAHPI_TRUE);
case SAHPI_EC_ENABLE:
valid_states = SAHPI_ES_DISABLED |
SAHPI_ES_ENABLED;
if (event_state & (~valid_states)) {
CRIT("Invalid event state.");
return(SAHPI_FALSE);
}
if (check_mutal_exclusion) {
if ((event_state & SAHPI_ES_DISABLED) &&
(event_state & SAHPI_ES_ENABLED)) {
CRIT("Mutally exclusive ENABLE event states defined");
return(SAHPI_FALSE);
}
}
return(SAHPI_TRUE);
case SAHPI_EC_AVAILABILITY:
valid_states = SAHPI_ES_RUNNING |
SAHPI_ES_TEST |
SAHPI_ES_POWER_OFF |
SAHPI_ES_ON_LINE |
SAHPI_ES_OFF_LINE |
SAHPI_ES_OFF_DUTY |
SAHPI_ES_DEGRADED |
SAHPI_ES_POWER_SAVE |
SAHPI_ES_INSTALL_ERROR;
if (event_state & (~valid_states)) {
CRIT("Invalid event state.");
return(SAHPI_FALSE);
}
/* ?? Any of these exclusive */
return(SAHPI_TRUE);
case SAHPI_EC_REDUNDANCY:
valid_states = SAHPI_ES_FULLY_REDUNDANT |
SAHPI_ES_REDUNDANCY_LOST |
SAHPI_ES_REDUNDANCY_DEGRADED |
SAHPI_ES_REDUNDANCY_LOST_SUFFICIENT_RESOURCES |
SAHPI_ES_NON_REDUNDANT_SUFFICIENT_RESOURCES |
SAHPI_ES_NON_REDUNDANT_INSUFFICIENT_RESOURCES |
SAHPI_ES_REDUNDANCY_DEGRADED_FROM_FULL |
SAHPI_ES_REDUNDANCY_DEGRADED_FROM_NON;
if (event_state & (~valid_states)) {
CRIT("Invalid event state.");
return(SAHPI_FALSE);
}
if (check_mutal_exclusion) {
/* Assume SAHPI_ES_REDUNDANCY_LOST or SAHPI_ES_REDUNDANCY_DEGRADED
must be set in addition to the bits that establish direction */
if (event_state & SAHPI_ES_FULLY_REDUNDANT) {
if (event_state != SAHPI_ES_FULLY_REDUNDANT) {
return(SAHPI_FALSE);
}
}
if (event_state & SAHPI_ES_REDUNDANCY_LOST) {
valid_states = SAHPI_ES_REDUNDANCY_LOST |
SAHPI_ES_REDUNDANCY_LOST_SUFFICIENT_RESOURCES |
SAHPI_ES_NON_REDUNDANT_SUFFICIENT_RESOURCES |
SAHPI_ES_NON_REDUNDANT_INSUFFICIENT_RESOURCES;
if (event_state & (~valid_states)) {
CRIT("Mutally exclusive REDUNDANCY_LOST event states defined");
return(SAHPI_FALSE);
}
}
if (event_state & SAHPI_ES_REDUNDANCY_DEGRADED) {
valid_states = SAHPI_ES_REDUNDANCY_DEGRADED |
SAHPI_ES_REDUNDANCY_DEGRADED_FROM_FULL |
SAHPI_ES_REDUNDANCY_DEGRADED_FROM_NON;
if (event_state & (~valid_states)) {
CRIT("Mutally exclusive REDUNDANCY_LOST event states defined");
return(SAHPI_FALSE);
}
}
if (event_state & SAHPI_ES_REDUNDANCY_DEGRADED_FROM_FULL) {
if (event_state & SAHPI_ES_REDUNDANCY_DEGRADED_FROM_NON) {
CRIT("Mutally exclusive REDUNDANCY_LOST event states defined");
return(SAHPI_FALSE);
}
}
if (event_state & SAHPI_ES_REDUNDANCY_LOST_SUFFICIENT_RESOURCES) {
if (event_state & SAHPI_ES_NON_REDUNDANT_SUFFICIENT_RESOURCES) {
CRIT("Mutally exclusive REDUNDANCY_LOST event states defined");
return(SAHPI_FALSE);
}
}
}
return(SAHPI_TRUE);
case SAHPI_EC_SENSOR_SPECIFIC:
case SAHPI_EC_GENERIC:
valid_states = SAHPI_ES_STATE_00 |
SAHPI_ES_STATE_01 |
SAHPI_ES_STATE_02 |
SAHPI_ES_STATE_03 |
SAHPI_ES_STATE_04 |
SAHPI_ES_STATE_05 |
SAHPI_ES_STATE_06 |
SAHPI_ES_STATE_07 |
SAHPI_ES_STATE_08 |
SAHPI_ES_STATE_09 |
SAHPI_ES_STATE_10 |
SAHPI_ES_STATE_11 |
SAHPI_ES_STATE_12 |
SAHPI_ES_STATE_13 |
SAHPI_ES_STATE_14;
if (event_state & (~valid_states)) {
CRIT("Invalid event state.");
return(SAHPI_FALSE);
}
return(SAHPI_TRUE);
default:
return(SAHPI_FALSE);
}
}
/**
* oh_valid_addevent:
* @event: Pointer to add event.
*
* Validates @event is a valid event for SaHpiEventAdd. This routines makes
* all the checks specified in the HPI spec to see if @event is valid.
*
* Returns:
* SA_OK - Normal operation.
* SA_ERR_HPI_INVALID_PARAMS - See HPI spec.
**/
SaErrorT oh_valid_addevent(SaHpiEventT *event)
{
if (!event) {
return(SA_ERR_HPI_INVALID_PARAMS);
}
if (event->Source != SAHPI_UNSPECIFIED_RESOURCE_ID ||
event->EventType != SAHPI_ET_USER ||
NULL == oh_lookup_severity(event->Severity) ||
event->Severity == SAHPI_ALL_SEVERITIES ||
!oh_valid_textbuffer(&(event->EventDataUnion.UserEvent.UserEventData))) {
return(SA_ERR_HPI_INVALID_PARAMS);
}
/* No check for implementation-specific restriction on to how much data may
be provided in the SAHPI_ET_USER event */
return(SA_OK);
}