/* * sensor.c * * MontaVista IPMI code for handling sensors * * Author: MontaVista Software, Inc. * Corey Minyard * source@mvista.com * * Copyright 2002,2003 MontaVista Software Inc. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License * as published by the Free Software Foundation; either version 2 of * the License, or (at your option) any later version. * * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * You should have received a copy of the GNU Lesser General Public * License along with this program; if not, write to the Free * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include struct ipmi_sensor_info_s { int destroyed; /* Indexed by LUN and sensor # */ ipmi_sensor_t **(sensors_by_idx[5]); /* Size of above sensor array, per LUN. This will be 0 if the LUN has no sensors. */ unsigned int idx_size[5]; /* In the above two, the 5th index is for non-standard sensors. */ ipmi_lock_t *idx_lock; /* Total number of sensors we have in this. */ unsigned int sensor_count; }; #define SENSOR_ID_LEN 32 /* 16 bytes are allowed for a sensor. */ struct ipmi_sensor_s { unsigned int usecount; ipmi_domain_t *domain; /* Domain I am in. */ ipmi_mc_t *mc; /* My owner, NOT the SMI mc (unless that happens to be my direct owner). */ ipmi_mc_t *source_mc; /* If the sensor came from the main SDR, this will be NULL. Otherwise, it will be the MC that owned the device SDR this came from. */ int source_idx; /* The index into the source array where this is stored. This will be -1 if it does not have a source index (ie it's a non-standard sensor) */ int source_recid; /* The SDR record ID the sensor came from. */ ipmi_sensor_t **source_array; /* This is the source array where the sensor is stored. */ int destroyed; /* After the sensor is added, it will not be reported immediately. Instead, it will wait until the usecount goes to zero before being reported. This marks that the add report is pending */ int add_pending; unsigned char owner; unsigned char channel; unsigned char lun; unsigned char num; /* For OEM sensors, the sending LUN might be different that the LUN we use for storage. */ unsigned char send_lun; ipmi_entity_t *entity; unsigned char entity_id; unsigned char entity_instance; /* Can the sensor be read? Event-only sensors cannot be read. */ unsigned int readable : 1; unsigned int entity_instance_logical : 1; unsigned int sensor_init_scanning : 1; unsigned int sensor_init_events : 1; unsigned int sensor_init_thresholds : 1; unsigned int sensor_init_hysteresis : 1; unsigned int sensor_init_type : 1; unsigned int sensor_init_pu_events : 1; unsigned int sensor_init_pu_scanning : 1; unsigned int ignore_if_no_entity : 1; unsigned int supports_auto_rearm : 1; unsigned int hysteresis_support : 2; unsigned int threshold_access : 2; unsigned int event_support : 2; unsigned int sensor_direction : 2; unsigned int ignore_for_presence : 1; int hot_swap_requester; int hot_swap_requester_val; unsigned char sensor_type; unsigned char event_reading_type; #define IPMI_SENSOR_GET_MASK_BIT(mask, bit) (((mask) >> (bit)) & 1) #define IPMI_SENSOR_SET_MASK_BIT(mask, bit, v) \ (mask) = v ? (mask) | (1 << (bit)) : (mask) & ~(1 << (bit)) uint16_t mask1; uint16_t mask2; uint16_t mask3; unsigned int analog_data_format : 2; unsigned int rate_unit : 3; unsigned int modifier_unit_use : 2; unsigned int percentage : 1; unsigned char base_unit; unsigned char modifier_unit; unsigned char linearization; struct { int m : 10; unsigned int tolerance : 6; int b : 10; int r_exp : 4; unsigned int accuracy_exp : 2; int accuracy : 10; int b_exp : 4; } conv[256]; unsigned int normal_min_specified : 1; unsigned int normal_max_specified : 1; unsigned int nominal_reading_specified : 1; unsigned char nominal_reading; unsigned char normal_max; unsigned char normal_min; unsigned char sensor_max; unsigned char sensor_min; unsigned char default_thresholds[6]; unsigned char positive_going_threshold_hysteresis; unsigned char negative_going_threshold_hysteresis; unsigned char oem1; /* Note that the ID is *not* nil terminated. */ enum ipmi_str_type_e id_type; unsigned int id_len; char id[SENSOR_ID_LEN]; /* The ID from the device SDR. */ const char *sensor_type_string; const char *event_reading_type_string; const char *rate_unit_string; const char *base_unit_string; const char *modifier_unit_string; /* A list of handlers to call when an event for the sensor comes in. */ locked_list_t *handler_list, *handler_list_cl; opq_t *waitq; ipmi_event_state_t event_state; /* Polymorphic functions. */ ipmi_sensor_cbs_t cbs; /* OEM info */ void *oem_info; ipmi_sensor_cleanup_oem_info_cb oem_info_cleanup_handler; ipmi_sensor_destroy_cb destroy_handler; void *destroy_handler_cb_data; /* Name we use for reporting. We add a ' ' onto the end, thus the +1. */ char name[IPMI_SENSOR_NAME_LEN+1]; /* Used for temporary linking. */ ipmi_sensor_t *tlink; /* Cruft. */ ipmi_sensor_threshold_event_handler_nd_cb threshold_event_handler; ipmi_sensor_discrete_event_handler_nd_cb discrete_event_handler; void *cb_data; }; static void sensor_final_destroy(ipmi_sensor_t *sensor); /*********************************************************************** * * Sensor ID handling. * **********************************************************************/ /* Must be called with the domain entity lock held. */ int i_ipmi_sensor_get(ipmi_sensor_t *sensor) { if (sensor->destroyed) return EINVAL; sensor->usecount++; return 0; } void i_ipmi_sensor_put(ipmi_sensor_t *sensor) { ipmi_domain_t *domain = sensor->domain; i_ipmi_domain_entity_lock(domain); if (sensor->usecount == 1) { if (sensor->add_pending) { sensor->add_pending = 0; i_ipmi_domain_entity_unlock(sensor->domain); i_ipmi_entity_call_sensor_handlers(sensor->entity, sensor, IPMI_ADDED); i_ipmi_domain_entity_lock(sensor->domain); } if (sensor->destroyed && (!sensor->waitq || (!opq_stuff_in_progress(sensor->waitq)))) { i_ipmi_domain_entity_unlock(domain); sensor_final_destroy(sensor); return; } } sensor->usecount--; i_ipmi_domain_entity_unlock(domain); } ipmi_sensor_id_t ipmi_sensor_convert_to_id(ipmi_sensor_t *sensor) { ipmi_sensor_id_t val; CHECK_SENSOR_LOCK(sensor); val.mcid = ipmi_mc_convert_to_id(sensor->mc); val.lun = sensor->lun; val.sensor_num = sensor->num; return val; } int ipmi_cmp_sensor_id(ipmi_sensor_id_t id1, ipmi_sensor_id_t id2) { int rv; rv = ipmi_cmp_mc_id(id1.mcid, id2.mcid); if (rv) return rv; if (id1.lun > id2.lun) return 1; if (id1.lun < id2.lun) return -1; if (id1.sensor_num > id2.sensor_num) return 1; if (id1.sensor_num < id2.sensor_num) return -1; return 0; } void ipmi_sensor_id_set_invalid(ipmi_sensor_id_t *id) { memset(id, 0, sizeof(*id)); } int ipmi_sensor_id_is_invalid(const ipmi_sensor_id_t *id) { return (id->mcid.domain_id.domain == NULL); } typedef struct mc_cb_info_s { ipmi_sensor_ptr_cb handler; void *cb_data; ipmi_sensor_id_t id; int err; } mc_cb_info_t; static void mc_cb(ipmi_mc_t *mc, void *cb_data) { mc_cb_info_t *info = cb_data; ipmi_sensor_info_t *sensors; ipmi_domain_t *domain = ipmi_mc_get_domain(mc); ipmi_sensor_t *sensor; ipmi_entity_t *entity = NULL; sensors = i_ipmi_mc_get_sensors(mc); i_ipmi_domain_entity_lock(domain); if (info->id.lun > 4) { info->err = EINVAL; goto out_unlock; } if (info->id.sensor_num >= sensors->idx_size[info->id.lun]) { info->err = EINVAL; goto out_unlock; } sensor = sensors->sensors_by_idx[info->id.lun][info->id.sensor_num]; if (!sensor) { info->err = EINVAL; goto out_unlock; } info->err = i_ipmi_entity_get(sensor->entity); if (info->err) goto out_unlock; entity = sensor->entity; info->err = i_ipmi_sensor_get(sensor); if (info->err) goto out_unlock; i_ipmi_domain_entity_unlock(domain); info->handler(sensor, info->cb_data); i_ipmi_sensor_put(sensor); i_ipmi_entity_put(entity); return; out_unlock: i_ipmi_domain_entity_unlock(domain); if (entity) i_ipmi_entity_put(entity); } int ipmi_sensor_pointer_cb(ipmi_sensor_id_t id, ipmi_sensor_ptr_cb handler, void *cb_data) { int rv; mc_cb_info_t info; if (id.lun >= 5) return EINVAL; info.handler = handler; info.cb_data = cb_data; info.id = id; info.err = 0; rv = ipmi_mc_pointer_cb(id.mcid, mc_cb, &info); if (!rv) rv = info.err; return rv; } int ipmi_sensor_pointer_noseq_cb(ipmi_sensor_id_t id, ipmi_sensor_ptr_cb handler, void *cb_data) { int rv; mc_cb_info_t info; if (id.lun >= 5) return EINVAL; info.handler = handler; info.cb_data = cb_data; info.id = id; info.err = 0; rv = ipmi_mc_pointer_noseq_cb(id.mcid, mc_cb, &info); if (!rv) rv = info.err; return rv; } typedef struct sensor_find_info_s { ipmi_sensor_id_t id; char *id_name; int rv; } sensor_find_info_t; static void sensor_search_cmp(ipmi_entity_t *entity, ipmi_sensor_t *sensor, void *cb_data) { sensor_find_info_t *info = cb_data; char id[33]; int rv; rv = ipmi_sensor_get_id(sensor, id, 33); if (rv) return; if (strcmp(info->id_name, id) == 0) { info->id = ipmi_sensor_convert_to_id(sensor); info->rv = 0; } } static void sensor_search(ipmi_entity_t *entity, void *cb_data) { sensor_find_info_t *info = cb_data; ipmi_entity_iterate_sensors(entity, sensor_search_cmp, info); } int ipmi_sensor_find_id(ipmi_domain_id_t domain_id, int entity_id, int entity_instance, int channel, int slave_address, char *id_name, ipmi_sensor_id_t *id) { int rv; ipmi_entity_id_t entity; sensor_find_info_t info; rv = ipmi_entity_find_id(domain_id, entity_id, entity_instance, channel, slave_address, &entity); if (rv) return rv; info.id_name = id_name; info.rv = EINVAL; rv = ipmi_entity_pointer_cb(entity, sensor_search, &info); if (!rv) rv = info.rv; if (!rv) *id = info.id; return rv; } /*********************************************************************** * * Various sensor allocation/deallocation/opq/etc. * **********************************************************************/ static int sensor_ok_to_use(ipmi_sensor_t *sensor) { return ( !sensor->destroyed && !i_ipmi_domain_in_shutdown(sensor->domain)); } static void sensor_set_name(ipmi_sensor_t *sensor); static void sensor_opq_ready2(ipmi_sensor_t *sensor, void *cb_data) { ipmi_sensor_op_info_t *info = cb_data; if (info->__handler) info->__handler(sensor, 0, info->__cb_data); } static int sensor_opq_ready(void *cb_data, int shutdown) { ipmi_sensor_op_info_t *info = cb_data; int rv; if (shutdown) { if (info->__handler) info->__handler(info->__sensor, ECANCELED, info->__cb_data); return OPQ_HANDLER_STARTED; } rv = ipmi_sensor_pointer_cb(info->__sensor_id, sensor_opq_ready2, info); if (rv) if (info->__handler) info->__handler(info->__sensor, rv, info->__cb_data); return OPQ_HANDLER_STARTED; } int ipmi_sensor_add_opq(ipmi_sensor_t *sensor, ipmi_sensor_op_cb handler, ipmi_sensor_op_info_t *info, void *cb_data) { if (sensor->destroyed) return EINVAL; info->__sensor = sensor; info->__sensor_id = ipmi_sensor_convert_to_id(sensor); info->__cb_data = cb_data; info->__handler = handler; if (!opq_new_op(sensor->waitq, sensor_opq_ready, info, 0)) return ENOMEM; return 0; } static void sensor_id_add_opq_cb(ipmi_sensor_t *sensor, void *cb_data) { ipmi_sensor_op_info_t *info = cb_data; info->__sensor = sensor; if (!opq_new_op(sensor->waitq, sensor_opq_ready, info, 0)) info->__err = ENOMEM; } int ipmi_sensor_id_add_opq(ipmi_sensor_id_t sensor_id, ipmi_sensor_op_cb handler, ipmi_sensor_op_info_t *info, void *cb_data) { int rv; info->__sensor_id = sensor_id; info->__cb_data = cb_data; info->__handler = handler; info->__err = 0; rv = ipmi_sensor_pointer_cb(sensor_id, sensor_id_add_opq_cb, info); if (!rv) rv = info->__err; return rv; } void ipmi_sensor_opq_done(ipmi_sensor_t *sensor) { /* Protect myself from NULL sensors. This way, it doesn't have to be done in each call. */ if (!sensor) return; /* This gets called on ECANCELLED error cases, if the sensor is already destroyed we need to clear out the opq. */ if (sensor->destroyed) { if (sensor->waitq) { opq_destroy(sensor->waitq); sensor->waitq = NULL; } return; } /* No check for the sensor lock. It will sometimes fail at destruction time. */ opq_op_done(sensor->waitq); } static void sensor_rsp_handler2(ipmi_sensor_t *sensor, void *cb_data) { ipmi_sensor_op_info_t *info = cb_data; if (info->__rsp_handler) info->__rsp_handler(sensor, 0, info->__rsp, info->__cb_data); } static void sensor_rsp_handler(ipmi_mc_t *mc, ipmi_msg_t *rsp, void *rsp_data) { ipmi_sensor_op_info_t *info = rsp_data; int rv; ipmi_sensor_t *sensor = info->__sensor; ipmi_entity_t *entity = NULL; if (sensor->destroyed) { i_ipmi_domain_entity_lock(sensor->domain); sensor->usecount++; rv = i_ipmi_entity_get(sensor->entity); if (! rv) entity = sensor->entity; i_ipmi_domain_entity_unlock(sensor->domain); if (info->__rsp_handler) info->__rsp_handler(sensor, ECANCELED, NULL, info->__cb_data); i_ipmi_sensor_put(sensor); if (entity) i_ipmi_entity_put(entity); return; } if (!mc) { i_ipmi_domain_entity_lock(sensor->domain); sensor->usecount++; rv = i_ipmi_entity_get(sensor->entity); if (! rv) entity = sensor->entity; i_ipmi_domain_entity_unlock(sensor->domain); if (info->__rsp_handler) info->__rsp_handler(sensor, ECANCELED, rsp, info->__cb_data); i_ipmi_sensor_put(sensor); if (entity) i_ipmi_entity_put(entity); return; } /* Call the next stage with the lock held. */ info->__rsp = rsp; rv = ipmi_sensor_pointer_cb(info->__sensor_id, sensor_rsp_handler2, info); if (rv) { int nrv; ipmi_log(IPMI_LOG_ERR_INFO, "%ssensor.c(sensor_rsp_handler):" " Could not convert sensor id to a pointer", MC_NAME(mc)); i_ipmi_domain_entity_lock(sensor->domain); sensor->usecount++; nrv = i_ipmi_entity_get(sensor->entity); if (! nrv) entity = sensor->entity; i_ipmi_domain_entity_unlock(sensor->domain); if (info->__rsp_handler) info->__rsp_handler(sensor, rv, NULL, info->__cb_data); i_ipmi_sensor_put(sensor); if (entity) i_ipmi_entity_put(entity); } } int ipmi_sensor_send_command(ipmi_sensor_t *sensor, ipmi_mc_t *mc, unsigned int lun, ipmi_msg_t *msg, ipmi_sensor_rsp_cb handler, ipmi_sensor_op_info_t *info, void *cb_data) { int rv; CHECK_MC_LOCK(mc); CHECK_SENSOR_LOCK(sensor); if (sensor->destroyed) return EINVAL; info->__sensor = sensor; info->__sensor_id = ipmi_sensor_convert_to_id(sensor); info->__cb_data = cb_data; info->__rsp_handler = handler; rv = ipmi_mc_send_command(mc, lun, msg, sensor_rsp_handler, info); return rv; } static int sensor_addr_response_handler(ipmi_domain_t *domain, ipmi_msgi_t *rspi) { ipmi_msg_t *msg = &rspi->msg; ipmi_sensor_op_info_t *info = rspi->data1; int rv; ipmi_sensor_t *sensor = info->__sensor; if (sensor->destroyed) { if (info->__rsp_handler) { i_ipmi_domain_mc_lock(sensor->domain); i_ipmi_mc_get(sensor->mc); i_ipmi_domain_mc_unlock(sensor->domain); i_ipmi_domain_entity_lock(sensor->domain); i_ipmi_entity_get(sensor->entity); sensor->usecount++; i_ipmi_domain_entity_unlock(sensor->domain); info->__rsp_handler(NULL, ECANCELED, NULL, info->__cb_data); i_ipmi_sensor_put(sensor); i_ipmi_mc_put(sensor->mc); i_ipmi_entity_put(sensor->entity); } return IPMI_MSG_ITEM_NOT_USED; } /* Call the next stage with the lock held. */ info->__rsp = msg; rv = ipmi_sensor_pointer_cb(info->__sensor_id, sensor_rsp_handler2, info); if (rv) { ipmi_log(IPMI_LOG_ERR_INFO, "%ssensor.c(sensor_addr_rsp_handler):" " Could not convert sensor id to a pointer", DOMAIN_NAME(domain)); if (info->__rsp_handler) { i_ipmi_domain_mc_lock(sensor->domain); i_ipmi_mc_get(sensor->mc); i_ipmi_domain_mc_unlock(sensor->domain); i_ipmi_domain_entity_lock(sensor->domain); i_ipmi_entity_get(sensor->entity); sensor->usecount++; i_ipmi_domain_entity_unlock(sensor->domain); info->__rsp_handler(sensor, rv, NULL, info->__cb_data); i_ipmi_sensor_put(sensor); i_ipmi_mc_put(sensor->mc); i_ipmi_entity_put(sensor->entity); } } return IPMI_MSG_ITEM_NOT_USED; } int ipmi_sensor_send_command_addr(ipmi_domain_t *domain, ipmi_sensor_t *sensor, ipmi_addr_t *addr, unsigned int addr_len, ipmi_msg_t *msg, ipmi_sensor_rsp_cb handler, ipmi_sensor_op_info_t *info, void *cb_data) { int rv; CHECK_SENSOR_LOCK(sensor); CHECK_MC_LOCK(sensor->mc); info->__sensor = sensor; info->__sensor_id = ipmi_sensor_convert_to_id(sensor); info->__cb_data = cb_data; info->__rsp_handler = handler; rv = ipmi_send_command_addr(domain, addr, addr_len, msg, sensor_addr_response_handler, info, NULL); return rv; } int ipmi_sensors_alloc(ipmi_mc_t *mc, ipmi_sensor_info_t **new_sensors) { ipmi_sensor_info_t *sensors; ipmi_domain_t *domain; os_handler_t *os_hnd; int i; int rv; CHECK_MC_LOCK(mc); domain = ipmi_mc_get_domain(mc); os_hnd = ipmi_domain_get_os_hnd(domain); sensors = ipmi_mem_alloc(sizeof(*sensors)); if (!sensors) return ENOMEM; rv = ipmi_create_lock_os_hnd(os_hnd, &sensors->idx_lock); if (rv) { ipmi_mem_free(sensors); return rv; } sensors->destroyed = 0; sensors->sensor_count = 0; for (i=0; i<5; i++) { sensors->sensors_by_idx[i] = NULL; sensors->idx_size[i] = 0; } *new_sensors = sensors; return 0; } unsigned int ipmi_sensors_get_count(ipmi_sensor_info_t *sensors) { return sensors->sensor_count; } int ipmi_sensor_alloc_nonstandard(ipmi_sensor_t **new_sensor) { ipmi_sensor_t *sensor; sensor = ipmi_mem_alloc(sizeof(*sensor)); if (!sensor) return ENOMEM; memset(sensor, 0, sizeof(*sensor)); sensor->hot_swap_requester = -1; sensor->usecount = 1; sensor->readable = 1; *new_sensor = sensor; return 0; } int ipmi_sensor_add_nonstandard(ipmi_mc_t *mc, ipmi_mc_t *source_mc, ipmi_sensor_t *sensor, unsigned int num, unsigned int send_lun, ipmi_entity_t *ent, ipmi_sensor_destroy_cb destroy_handler, void *destroy_handler_cb_data) { ipmi_sensor_info_t *sensors = i_ipmi_mc_get_sensors(mc); ipmi_domain_t *domain; os_handler_t *os_hnd; void *link; int err; unsigned int i; CHECK_MC_LOCK(mc); CHECK_ENTITY_LOCK(ent); domain = ipmi_mc_get_domain(mc); os_hnd = ipmi_domain_get_os_hnd(domain); if ((num >= 256) && (num != UINT_MAX)) return EINVAL; i_ipmi_domain_entity_lock(domain); ipmi_lock(sensors->idx_lock); if (num == UINT_MAX){ for (i=0; iidx_size[4]; i++) { if (! sensors->sensors_by_idx[4][i]) break; } num = i; if (num >= 256) { err = EAGAIN; goto out_err; } } if (num >= sensors->idx_size[4]) { ipmi_sensor_t **new_array; unsigned int new_size; unsigned int i; /* Allocate the array in multiples of 16 (to avoid thrashing malloc too much). */ new_size = ((num / 16) * 16) + 16; new_array = ipmi_mem_alloc(sizeof(*new_array) * new_size); if (!new_array) { err = ENOMEM; goto out_err; } if (sensors->sensors_by_idx[4]) { memcpy(new_array, sensors->sensors_by_idx[4], sizeof(*new_array) * (sensors->idx_size[4])); ipmi_mem_free(sensors->sensors_by_idx[4]); } for (i=sensors->idx_size[4]; isensors_by_idx[4] = new_array; sensors->idx_size[4] = new_size; } sensor->waitq = opq_alloc(os_hnd); if (! sensor->waitq) { err = ENOMEM; goto out_err; } sensor->handler_list = locked_list_alloc(os_hnd); if (! sensor->handler_list) { opq_destroy(sensor->waitq); err = ENOMEM; goto out_err; } sensor->handler_list_cl = locked_list_alloc(os_hnd); if (! sensor->handler_list_cl) { locked_list_destroy(sensor->handler_list); opq_destroy(sensor->waitq); err = ENOMEM; goto out_err; } link = locked_list_alloc_entry(); if (!link) { opq_destroy(sensor->waitq); sensor->waitq = NULL; locked_list_destroy(sensor->handler_list); locked_list_destroy(sensor->handler_list_cl); sensor->handler_list = NULL; err = ENOMEM; goto out_err; } sensor->domain = domain; sensor->mc = mc; sensor->source_mc = source_mc; sensor->lun = 4; sensor->send_lun = send_lun; sensor->num = num; sensor->source_idx = -1; sensor->source_array = NULL; if (!sensors->sensors_by_idx[4][num]) sensors->sensor_count++; sensors->sensors_by_idx[4][num] = sensor; sensor->entity = ent; sensor->entity_id = ipmi_entity_get_entity_id(ent); sensor->entity_instance = ipmi_entity_get_entity_instance(ent); sensor->destroy_handler = destroy_handler; sensor->destroy_handler_cb_data = destroy_handler_cb_data; sensor_set_name(sensor); ipmi_unlock(sensors->idx_lock); i_ipmi_domain_entity_unlock(domain); ipmi_entity_add_sensor(ent, sensor, link); sensor->add_pending = 1; return 0; out_err: ipmi_unlock(sensors->idx_lock); i_ipmi_domain_entity_unlock(domain); return err; } typedef struct threshold_handler_cl_info_s { ipmi_sensor_threshold_event_cb handler; void *handler_data; } threshold_handler_cl_info_t; static int iterate_threshold_handler_cl(void *cb_data, void *item1, void *item2) { threshold_handler_cl_info_t *info = cb_data; ipmi_sensor_threshold_event_cl_cb handler = item1; handler(info->handler, info->handler_data, item2); return LOCKED_LIST_ITER_CONTINUE; } typedef struct discrete_handler_cl_info_s { ipmi_sensor_discrete_event_cb handler; void *handler_data; } discrete_handler_cl_info_t; static int iterate_discrete_handler_cl(void *cb_data, void *item1, void *item2) { discrete_handler_cl_info_t *info = cb_data; ipmi_sensor_discrete_event_cl_cb handler = item1; handler(info->handler, info->handler_data, item2); return LOCKED_LIST_ITER_CONTINUE; } static int handler_list_cleanup(void *cb_data, void *item1, void *item2) { ipmi_sensor_t *sensor = cb_data; if (sensor->event_reading_type == IPMI_EVENT_READING_TYPE_THRESHOLD) { threshold_handler_cl_info_t info; info.handler = item1; info.handler_data = item2; locked_list_iterate(sensor->handler_list_cl, iterate_threshold_handler_cl, &info); } else { discrete_handler_cl_info_t info; info.handler = item1; info.handler_data = item2; locked_list_iterate(sensor->handler_list_cl, iterate_discrete_handler_cl, &info); } return LOCKED_LIST_ITER_CONTINUE; } static void sensor_final_destroy(ipmi_sensor_t *sensor) { i_ipmi_entity_get(sensor->entity); i_ipmi_entity_call_sensor_handlers(sensor->entity, sensor, IPMI_DELETED); sensor->mc = NULL; if (sensor->destroy_handler) sensor->destroy_handler(sensor, sensor->destroy_handler_cb_data); if (sensor->waitq) opq_destroy(sensor->waitq); if (sensor->handler_list) { locked_list_iterate(sensor->handler_list, handler_list_cleanup, sensor); locked_list_destroy(sensor->handler_list); } if (sensor->handler_list_cl) locked_list_destroy(sensor->handler_list_cl); if (sensor->entity) ipmi_entity_remove_sensor(sensor->entity, sensor); if (sensor->oem_info_cleanup_handler) sensor->oem_info_cleanup_handler(sensor, sensor->oem_info); i_ipmi_entity_put(sensor->entity); ipmi_mem_free(sensor); } int ipmi_sensor_destroy(ipmi_sensor_t *sensor) { ipmi_sensor_info_t *sensors; ipmi_mc_t *mc = sensor->mc; i_ipmi_domain_mc_lock(sensor->domain); i_ipmi_mc_get(mc); i_ipmi_domain_mc_unlock(sensor->domain); sensors = i_ipmi_mc_get_sensors(sensor->mc); ipmi_lock(sensors->idx_lock); if (sensor == sensors->sensors_by_idx[sensor->lun][sensor->num]) { sensors->sensor_count--; sensors->sensors_by_idx[sensor->lun][sensor->num] = NULL; } i_ipmi_sensor_get(sensor); if (sensor->source_array) sensor->source_array[sensor->source_idx] = NULL; ipmi_unlock(sensors->idx_lock); sensor->destroyed = 1; i_ipmi_sensor_put(sensor); i_ipmi_mc_put(mc); return 0; } int ipmi_sensors_destroy(ipmi_sensor_info_t *sensors) { unsigned int i, j; if (sensors->destroyed) return EINVAL; sensors->destroyed = 1; for (i=0; i<=4; i++) { for (j=0; jidx_size[i]; j++) { if (sensors->sensors_by_idx[i][j]) { ipmi_sensor_destroy(sensors->sensors_by_idx[i][j]); } } if (sensors->sensors_by_idx[i]) ipmi_mem_free(sensors->sensors_by_idx[i]); } if (sensors->idx_lock) ipmi_destroy_lock(sensors->idx_lock); ipmi_mem_free(sensors); return 0; } static void sensor_set_name(ipmi_sensor_t *sensor) { int length; length = ipmi_entity_get_name(sensor->entity, sensor->name, sizeof(sensor->name)-2); sensor->name[length] = '.'; length++; length += snprintf(sensor->name+length, IPMI_SENSOR_NAME_LEN-length-2, "%s", sensor->id); sensor->name[length] = ' '; length++; sensor->name[length] = '\0'; length++; } const char * i_ipmi_sensor_name(const ipmi_sensor_t *sensor) { return sensor->name; } int ipmi_sensor_get_name(ipmi_sensor_t *sensor, char *name, int length) { int slen; if (length <= 0) return 0; /* Never changes, no lock needed. */ slen = strlen(sensor->name); if (slen == 0) { if (name) *name = '\0'; goto out; } slen -= 1; /* Remove the trailing ' ' */ if (slen >= length) slen = length - 1; if (name) { memcpy(name, sensor->name, slen); name[slen] = '\0'; } out: return slen; } /*********************************************************************** * * Sensor SDR handling * **********************************************************************/ static int get_sensors_from_sdrs(ipmi_domain_t *domain, ipmi_mc_t *source_mc, ipmi_sdr_info_t *sdrs, ipmi_sensor_t ***sensors, unsigned int *sensor_count) { ipmi_sdr_t sdr; unsigned int count; ipmi_sensor_t **s = NULL; unsigned int p, s_size = 0; int val; int rv; unsigned int i; int j; int share_count; int id_string_mod_type; int entity_instance_incr; int id_string_modifier_offset; unsigned char *str; unsigned int str_len; rv = ipmi_get_sdr_count(sdrs, &count); if (rv) { ipmi_log(IPMI_LOG_WARNING, "%ssensor.c(get_sensors_from_sdrs):" " Could not fetch SDR count fron the SDR record.", MC_NAME(source_mc)); goto out_err; } /* Get a real count on the number of sensors, since a single SDR can contain multiple sensors. */ p = 0; for (i=0; isource_recid = sdr.record_id; s[p]->hot_swap_requester = -1; s[p]->waitq = opq_alloc(ipmi_domain_get_os_hnd(domain)); if (!s[p]->waitq) goto out_err_enomem; s[p]->handler_list_cl = locked_list_alloc(ipmi_domain_get_os_hnd(domain)); if (! s[p]->handler_list_cl) { opq_destroy(s[p]->waitq); goto out_err_enomem; } s[p]->handler_list = locked_list_alloc(ipmi_domain_get_os_hnd(domain)); if (! s[p]->handler_list) { locked_list_destroy(s[i]->handler_list_cl); opq_destroy(s[p]->waitq); goto out_err_enomem; } s[p]->destroyed = 0; s[p]->destroy_handler = NULL; rv = i_ipmi_find_or_create_mc_by_slave_addr(domain, sdr.data[1] >> 4, sdr.data[0], &(s[p]->mc)); if (rv) { ipmi_log(IPMI_LOG_WARNING, "%ssensor.c(get_sensors_from_sdrs):" " Could not create MC for SDR record %d, channel %d" " owner 0x%x: %d", MC_NAME(source_mc), i, sdr.data[1] >> 4, sdr.data[0], rv); goto out_err; } share_count = 0; id_string_mod_type = 0; entity_instance_incr = 0; id_string_modifier_offset = 0; s[p]->usecount = 1; s[p]->domain = domain; s[p]->source_mc = source_mc; s[p]->source_idx = p; s[p]->source_array = s; s[p]->owner = sdr.data[0]; s[p]->channel = sdr.data[1] >> 4; s[p]->lun = sdr.data[1] & 0x03; s[p]->send_lun = s[p]->lun; s[p]->num = sdr.data[2]; s[p]->entity_id = sdr.data[3]; s[p]->entity_instance_logical = sdr.data[4] >> 7; s[p]->entity_instance = sdr.data[4] & 0x7f; if ((sdr.type == 1) || (sdr.type == 2)) { s[p]->readable = 1; s[p]->sensor_init_scanning = (sdr.data[5] >> 6) & 1; s[p]->sensor_init_events = (sdr.data[5] >> 5) & 1; s[p]->sensor_init_thresholds = (sdr.data[5] >> 4) & 1; s[p]->sensor_init_hysteresis = (sdr.data[5] >> 3) & 1; s[p]->sensor_init_type = (sdr.data[5] >> 2) & 1; s[p]->sensor_init_pu_events = (sdr.data[5] >> 1) & 1; s[p]->sensor_init_pu_scanning = (sdr.data[5] >> 0) & 1; s[p]->ignore_if_no_entity = (sdr.data[6] >> 7) & 1; s[p]->supports_auto_rearm = (sdr.data[6] >> 6) & 1 ; s[p]->hysteresis_support = (sdr.data[6] >> 4) & 3; s[p]->threshold_access = (sdr.data[6] >> 2) & 3; s[p]->event_support = sdr.data[6] & 3; s[p]->sensor_type = sdr.data[7]; s[p]->event_reading_type = sdr.data[8]; s[p]->mask1 = ipmi_get_uint16(sdr.data+9); s[p]->mask2 = ipmi_get_uint16(sdr.data+11); s[p]->mask3 = ipmi_get_uint16(sdr.data+13); s[p]->analog_data_format = (sdr.data[15] >> 6) & 3; s[p]->rate_unit = (sdr.data[15] >> 3) & 7; s[p]->modifier_unit_use = (sdr.data[15] >> 1) & 3; s[p]->percentage = sdr.data[15] & 1; s[p]->base_unit = sdr.data[16]; s[p]->modifier_unit = sdr.data[17]; } if (sdr.type == 1) { /* A full sensor record. */ s[p]->linearization = sdr.data[18] & 0x7f; if (s[p]->linearization <= 11) { for (j=0; j<256; j++) { s[p]->conv[j].m = sdr.data[19] | ((sdr.data[20] & 0xc0) << 2); s[p]->conv[j].tolerance = sdr.data[20] & 0x3f; s[p]->conv[j].b = sdr.data[21] | ((sdr.data[22] & 0xc0) << 2); s[p]->conv[j].accuracy = ((sdr.data[22] & 0x3f) | ((sdr.data[23] & 0xf0) << 2)); s[p]->conv[j].accuracy_exp = (sdr.data[23] >> 2) & 0x3; s[p]->conv[j].r_exp = (sdr.data[24] >> 4) & 0xf; s[p]->conv[j].b_exp = sdr.data[24] & 0xf; } } s[p]->sensor_direction = sdr.data[23] & 0x3; s[p]->normal_min_specified = (sdr.data[25] >> 2) & 1; s[p]->normal_max_specified = (sdr.data[25] >> 1) & 1; s[p]->nominal_reading_specified = sdr.data[25] & 1; s[p]->nominal_reading = sdr.data[26]; s[p]->normal_max = sdr.data[27]; s[p]->normal_min = sdr.data[28]; s[p]->sensor_max = sdr.data[29]; s[p]->sensor_min = sdr.data[30]; s[p]->default_thresholds[IPMI_UPPER_NON_RECOVERABLE]= sdr.data[31]; s[p]->default_thresholds[IPMI_UPPER_CRITICAL] = sdr.data[32]; s[p]->default_thresholds[IPMI_UPPER_NON_CRITICAL] = sdr.data[33]; s[p]->default_thresholds[IPMI_LOWER_NON_RECOVERABLE] = sdr.data[34]; s[p]->default_thresholds[IPMI_LOWER_CRITICAL] = sdr.data[35]; s[p]->default_thresholds[IPMI_LOWER_NON_CRITICAL] = sdr.data[36]; s[p]->positive_going_threshold_hysteresis = sdr.data[37]; s[p]->negative_going_threshold_hysteresis = sdr.data[38]; s[p]->oem1 = sdr.data[41]; str = sdr.data + 42; str_len = sdr.length - 42; if (s[p]->entity) sensor_set_name(s[p]); } else if (sdr.type == 2) { /* FIXME - make sure this is not a threshold sensor. The question is, what do I do if it is? */ /* A short sensor record. */ s[p]->sensor_direction = (sdr.data[18] >> 6) & 0x3; s[p]->positive_going_threshold_hysteresis = sdr.data[20]; s[p]->negative_going_threshold_hysteresis = sdr.data[21]; s[p]->oem1 = sdr.data[25]; str = sdr.data + 26; str_len = sdr.length - 26; share_count = sdr.data[18] & 0x0f; if (share_count == 0) share_count = 1; id_string_mod_type = (sdr.data[18] >> 4) & 0x3; entity_instance_incr = (sdr.data[19] >> 7) & 0x01; id_string_modifier_offset = sdr.data[19] & 0x7f; } else { /* Event-only sensor. It is not readable. */ s[p]->sensor_type = sdr.data[5]; s[p]->event_reading_type = sdr.data[6]; s[p]->oem1 = sdr.data[9]; str = sdr.data + 10; str_len = sdr.length - 10; share_count = sdr.data[7] & 0x0f; if (share_count == 0) share_count = 1; id_string_mod_type = (sdr.data[7] >> 4) & 0x3; entity_instance_incr = (sdr.data[8] >> 7) & 0x01; id_string_modifier_offset = sdr.data[8] & 0x7f; } rv = ipmi_get_device_string(&str, str_len, s[p]->id, IPMI_STR_SDR_SEMANTICS, 0, &s[p]->id_type, SENSOR_ID_LEN, &s[p]->id_len); if (rv) { ipmi_log(IPMI_LOG_WARNING, "%ssensor.c(get_sensors_from_sdrs):" " Error getting device ID string from SDR record %d: %d," " this sensor will be named **INVALID**", MC_NAME(source_mc), sdr.record_id, rv); strncpy(s[p]->id, "**INVALID**", sizeof(s[p]->id)); s[p]->id_len = strlen(s[p]->id); s[p]->id_type = IPMI_ASCII_STR; } if (share_count > 1) { /* Duplicate the sensor records for each instance. Go backwards to avoid destroying the first one until we finish the others. */ for (j=share_count-1; j>=0; j--) { int len; if (j != 0) { /* The first one is already allocated, we are using it to copy to the other ones, so this is not necessary. We still have to iterate the first one to set its string name, though. */ s[p+j] = ipmi_mem_alloc(sizeof(ipmi_sensor_t)); if (!s[p+j]) goto out_err_enomem; memcpy(s[p+j], s[p], sizeof(ipmi_sensor_t)); /* In case of error */ s[p+j]->handler_list = NULL; /* For every sensor except the first, increment the usage count for the MC so that it will decrement properly. This cannot fail because we have already gotten it before. */ i_ipmi_find_or_create_mc_by_slave_addr(domain, s[p+j]->channel, s[p+j]->owner, &(s[p+j]->mc)); s[p+j]->waitq = opq_alloc(ipmi_domain_get_os_hnd(domain)); if (!s[p+j]->waitq) goto out_err_enomem; s[p+j]->handler_list_cl = locked_list_alloc(ipmi_domain_get_os_hnd(domain)); if (! s[p+j]->handler_list_cl) goto out_err_enomem; s[p+j]->handler_list = locked_list_alloc(ipmi_domain_get_os_hnd(domain)); if (! s[p+j]->handler_list) goto out_err_enomem; s[p+j]->num += j; if (entity_instance_incr & 0x80) { s[p+j]->entity_instance += j; } s[p+j]->source_idx += j; } val = id_string_modifier_offset + j; len = s[p+j]->id_len; switch (id_string_mod_type) { case 0: /* Numeric */ if ((val / 10) > 0) { if (len < SENSOR_ID_LEN) { s[p+j]->id[len] = (val/10) + '0'; len++; } } if (len < SENSOR_ID_LEN) { s[p+j]->id[len] = (val%10) + '0'; len++; } break; case 1: /* Alpha */ if ((val / 26) > 0) { if (len < SENSOR_ID_LEN) { s[p+j]->id[len] = (val/26) + 'A'; len++; } } if (len < SENSOR_ID_LEN) { s[p+j]->id[len] = (val%26) + 'A'; len++; } break; /* FIXME - unicode handling? */ } s[p+j]->id_len = len; if (s[p+j]->entity) sensor_set_name(s[p+j]); } p += share_count; } else p++; } *sensors = s; *sensor_count = s_size; return 0; out_err_enomem: rv = ENOMEM; ipmi_log(IPMI_LOG_WARNING, "%ssensor.c(get_sensors_from_sdrs):" " Out of memory while processing the SDRS.", MC_NAME(source_mc)); out_err: if (s) { for (i=0; imc) i_ipmi_mc_put(s[i]->mc); if (s[i]->waitq) opq_destroy(s[i]->waitq); if (s[i]->handler_list) locked_list_destroy(s[i]->handler_list); if (s[i]->handler_list_cl) locked_list_destroy(s[i]->handler_list_cl); ipmi_mem_free(s[i]); } ipmi_mem_free(s); } return rv; } static void handle_new_sensor(ipmi_domain_t *domain, ipmi_sensor_t *sensor, void *link) { /* Call this before the OEM call so the OEM call can replace it. */ sensor->cbs = ipmi_standard_sensor_cb; sensor->sensor_type_string = ipmi_get_sensor_type_string(sensor->sensor_type); sensor->event_reading_type_string = ipmi_get_event_reading_type_string(sensor->event_reading_type); sensor->rate_unit_string = ipmi_get_rate_unit_string(sensor->rate_unit); sensor->base_unit_string = ipmi_get_unit_type_string(sensor->base_unit); sensor->modifier_unit_string = ipmi_get_unit_type_string(sensor->modifier_unit); sensor_set_name(sensor); if ((sensor->source_mc) && (i_ipmi_mc_new_sensor(sensor->source_mc, sensor->entity, sensor, link))) { /* Nothing to do, OEM code handled the sensor. */ } else { ipmi_entity_add_sensor(sensor->entity, sensor, link); } i_call_new_sensor_handlers(domain, sensor); } static int cmp_sensor(ipmi_sensor_t *s1, ipmi_sensor_t *s2) { int i; if (s1->entity_instance_logical != s2->entity_instance_logical) return 0; if (s1->sensor_init_scanning != s2->sensor_init_scanning) return 0; if (s1->sensor_init_events != s2->sensor_init_events) return 0; if (s1->sensor_init_thresholds != s2->sensor_init_thresholds) return 0; if (s1->sensor_init_hysteresis != s2->sensor_init_hysteresis) return 0; if (s1->sensor_init_type != s2->sensor_init_type) return 0; if (s1->sensor_init_pu_events != s2->sensor_init_pu_events) return 0; if (s1->sensor_init_pu_scanning != s2->sensor_init_pu_scanning) return 0; if (s1->ignore_if_no_entity != s2->ignore_if_no_entity) return 0; if (s1->supports_auto_rearm != s2->supports_auto_rearm) return 0; if (s1->hysteresis_support != s2->hysteresis_support) return 0; if (s1->threshold_access != s2->threshold_access) return 0; if (s1->event_support != s2->event_support) return 0; if (s1->sensor_type != s2->sensor_type) return 0; if (s1->event_reading_type != s2->event_reading_type) return 0; if (s1->mask1 != s2->mask1) return 0; if (s1->mask2 != s2->mask2) return 0; if (s1->mask3 != s2->mask3) return 0; if (s1->analog_data_format != s2->analog_data_format) return 0; if (s1->rate_unit != s2->rate_unit) return 0; if (s1->modifier_unit_use != s2->modifier_unit_use) return 0; if (s1->percentage != s2->percentage) return 0; if (s1->base_unit != s2->base_unit) return 0; if (s1->modifier_unit != s2->modifier_unit) return 0; if (s1->linearization != s2->linearization) return 0; if (s1->linearization <= 11) { if (s1->conv[0].m != s2->conv[0].m) return 0; if (s1->conv[0].tolerance != s2->conv[0].tolerance) return 0; if (s1->conv[0].b != s2->conv[0].b) return 0; if (s1->conv[0].accuracy != s2->conv[0].accuracy) return 0; if (s1->conv[0].accuracy_exp != s2->conv[0].accuracy_exp) return 0; if (s1->conv[0].r_exp != s2->conv[0].r_exp) return 0; if (s1->conv[0].b_exp != s2->conv[0].b_exp) return 0; } if (s1->normal_min_specified != s2->normal_min_specified) return 0; if (s1->normal_max_specified != s2->normal_max_specified) return 0; if (s1->nominal_reading_specified != s2->nominal_reading_specified) return 0; if (s1->nominal_reading != s2->nominal_reading) return 0; if (s1->normal_max != s2->normal_max) return 0; if (s1->normal_min != s2->normal_min) return 0; if (s1->sensor_max != s2->sensor_max) return 0; if (s1->sensor_min != s2->sensor_min) return 0; for (i=0; i<6; i++) { if (s1->default_thresholds[i] != s2->default_thresholds[i]) return 0; } if (s1->positive_going_threshold_hysteresis != s2->positive_going_threshold_hysteresis) return 0; if (s1->negative_going_threshold_hysteresis != s2->negative_going_threshold_hysteresis) return 0; if (s1->oem1 != s2->oem1) return 0; if (s1->id_type != s2->id_type) return 0; if (s1->id_len != s2->id_len) return 0; if (memcmp(s1->id, s2->id, s1->id_len) != 0) return 0; return 1; } enum entity_list_op { ENT_LIST_OLD, ENT_LIST_NEW, ENT_LIST_DUP }; typedef struct entity_list_s { ipmi_entity_t *ent; ipmi_sensor_t *sensor; ipmi_sensor_t *osensor; ipmi_mc_t *mc; enum entity_list_op op; struct entity_list_s *next; } entity_list_t; /* Assume it has enough space for one pointer. */ struct locked_list_entry_s { locked_list_entry_t *next; }; int ipmi_sensor_handle_sdrs(ipmi_domain_t *domain, ipmi_mc_t *source_mc, ipmi_sdr_info_t *sdrs) { int rv; unsigned int i, j; ipmi_sensor_t **sdr_sensors = NULL; ipmi_sensor_t **old_sdr_sensors; unsigned int old_count; unsigned int count = 0; ipmi_entity_info_t *ents; ipmi_entity_t *ent; entity_list_t *new_sensors = NULL; entity_list_t *del_sensors = NULL; entity_list_t *ent_item; entity_list_t *new_ent_item; locked_list_entry_t *link, *links = NULL; ipmi_sensor_t **sens_tmp; CHECK_DOMAIN_LOCK(domain); if (source_mc) CHECK_MC_LOCK(source_mc); rv = get_sensors_from_sdrs(domain, source_mc, sdrs, &sdr_sensors, &count); if (rv) goto out_err; ents = ipmi_domain_get_entities(domain); /* Pre-allocate all the links we will need for registering sensors with the entities, and we make sure all the entities exist. */ for (i=0; imc), ipmi_mc_get_address(nsensor->mc), i, nsensor->entity_id, nsensor->entity_instance, "", IPMI_ASCII_STR, 0, NULL, NULL, &ent); if (rv) goto out_err_free; nsensor->entity = ent; sensors = i_ipmi_mc_get_sensors(nsensor->mc); ipmi_lock(sensors->idx_lock); if (nsensor->num >= sensors->idx_size[nsensor->lun]) { /* There's not enough room in the sensor repository for the new item, so expand the array. */ ipmi_sensor_t **new_by_idx; unsigned int new_size = nsensor->num+10; new_by_idx = ipmi_mem_alloc(sizeof(ipmi_sensor_t *) * new_size); if (!new_by_idx) { ipmi_unlock(sensors->idx_lock); rv = ENOMEM; i_ipmi_entity_put(ent); goto out_err_free; } if (sensors->sensors_by_idx[nsensor->lun]) { memcpy(new_by_idx, sensors->sensors_by_idx[nsensor->lun], (sensors->idx_size[nsensor->lun] * sizeof(ipmi_sensor_t *))); ipmi_mem_free(sensors->sensors_by_idx[nsensor->lun]); } for (j=sensors->idx_size[nsensor->lun]; jsensors_by_idx[nsensor->lun] = new_by_idx; sensors->idx_size[nsensor->lun] = new_size; } ipmi_unlock(sensors->idx_lock); /* Keep track of each entity/sensor pair. */ new_ent_item = ipmi_mem_alloc(sizeof(*new_ent_item)); if (!new_ent_item) { i_ipmi_entity_put(ent); goto out_err_free; } new_ent_item->ent = ent; new_ent_item->sensor = nsensor; new_ent_item->osensor = NULL; new_ent_item->mc = nsensor->mc; new_ent_item->op = ENT_LIST_OLD; new_ent_item->next = new_sensors; new_sensors = new_ent_item; /* Pre-allocate link entries for putting the sensor into the entity. */ link = locked_list_alloc_entry(); if (!link) goto out_err_free; link->next = links; links = link; } } /* Check for duplicate sensor numbers in the new sensor set. */ sens_tmp = ipmi_mem_alloc(256 * sizeof(ipmi_sensor_t **)); if (!sens_tmp) { rv = ENOMEM; goto out_err_free; } memset(sens_tmp, 0, 256 * sizeof(ipmi_sensor_t **)); ent_item = new_sensors; while (ent_item) { ipmi_sensor_t *nsensor = ent_item->sensor; ipmi_sensor_t *csensor; if ((!ent_item->ent) || (!nsensor)) { ent_item = ent_item->next; continue; } csensor = sens_tmp[nsensor->num]; while (csensor) { if ((csensor->lun == nsensor->lun) && (csensor->num == nsensor->num) && (csensor->mc == nsensor->mc)) { break; } csensor = csensor->tlink; } if (csensor) { ipmi_log(IPMI_LOG_WARNING, "%ssensor.c(ipmi_sensor_handle_sdrs):" " SDR record %d has the same sensor number as record" " %d in the repository. Ignoring second sensor." " Fix your SDRs!", SENSOR_NAME(nsensor), csensor->source_recid, nsensor->source_recid); ent_item->op = ENT_LIST_DUP; ent_item->osensor = NULL; } else { nsensor->tlink = sens_tmp[nsensor->num]; sens_tmp[nsensor->num] = nsensor; } ent_item = ent_item->next; } ipmi_mem_free(sens_tmp); i_ipmi_domain_entity_lock(domain); i_ipmi_get_sdr_sensors(domain, source_mc, &old_sdr_sensors, &old_count); ent_item = new_sensors; while (ent_item) { ipmi_sensor_t *nsensor = ent_item->sensor; ipmi_sensor_info_t *sensors; if ((!ent_item->ent) || (!nsensor) || (ent_item->op == ENT_LIST_DUP)) { ent_item = ent_item->next; continue; } sensors = i_ipmi_mc_get_sensors(nsensor->mc); ipmi_lock(sensors->idx_lock); if (sensors->sensors_by_idx[nsensor->lun] && (nsensor->num < sensors->idx_size[nsensor->lun]) && sensors->sensors_by_idx[nsensor->lun][nsensor->num]) { /* A sensor is already there. */ ipmi_sensor_t *osensor = sensors->sensors_by_idx[nsensor->lun][nsensor->num]; if (cmp_sensor(nsensor, osensor)) { /* Since the data is the same, there is no need to get the old sensor entity or mc, since they are already gotten by the new sensor. */ ent_item->op = ENT_LIST_DUP; ent_item->osensor = osensor; } else { /* We have to delete the old sensor. */ new_ent_item = ipmi_mem_alloc(sizeof(*new_ent_item)); if (!new_ent_item) { ipmi_unlock(sensors->idx_lock); rv = ENOMEM; goto out_err_free_unlock; } /* It's possible this can fail, but that means that the MC is currently being destroyed. No big deal, just ignore it. */ new_ent_item->mc = NULL; i_ipmi_find_or_create_mc_by_slave_addr(domain, osensor->channel, osensor->owner, &new_ent_item->mc); i_ipmi_entity_get(osensor->entity); i_ipmi_sensor_get(osensor); new_ent_item->ent = osensor->entity; new_ent_item->sensor = osensor; new_ent_item->next = del_sensors; del_sensors = new_ent_item; ent_item->op = ENT_LIST_NEW; } } else { ent_item->op = ENT_LIST_NEW; } ipmi_unlock(sensors->idx_lock); ent_item = ent_item->next; } i_ipmi_domain_entity_unlock(domain); /* After this point, the operation cannot fail. Nothing above this actually changes anything, it just gets it ready. Now we put into place all the changes. */ /* First delete the sensors that we are replacing. */ ent_item = del_sensors; while (ent_item) { ipmi_sensor_t *osensor = ent_item->sensor; if (osensor->source_array) { osensor->source_array[osensor->source_idx] = NULL; osensor->source_array = NULL; } /* Note that the actual destroy is deferred until we put the sensor. */ ipmi_sensor_destroy(osensor); ent_item = ent_item->next; } ent_item = new_sensors; while (ent_item) { ipmi_sensor_t *nsensor = ent_item->sensor; ipmi_sensor_t *osensor = ent_item->osensor; ipmi_sensor_info_t *sensors; if ((!ent_item->ent) || (!nsensor)) { ent_item = ent_item->next; continue; } sensors = i_ipmi_mc_get_sensors(nsensor->mc); ipmi_lock(sensors->idx_lock); switch (ent_item->op) { case ENT_LIST_NEW: sensors->sensors_by_idx[nsensor->lun][nsensor->num] = nsensor; sensors->sensor_count++; link = links; links = link->next; handle_new_sensor(domain, nsensor, link); break; case ENT_LIST_OLD: break; case ENT_LIST_DUP: /* They compare, prefer to keep the old data. */ i = nsensor->source_idx; opq_destroy(nsensor->waitq); locked_list_destroy(nsensor->handler_list); locked_list_destroy(nsensor->handler_list_cl); ipmi_mem_free(nsensor); ent_item->sensor = NULL; sdr_sensors[i] = osensor; if (osensor) { if (osensor->source_array) osensor->source_array[osensor->source_idx] = NULL; osensor->source_idx = i; osensor->source_array = sdr_sensors; } break; } ipmi_unlock(sensors->idx_lock); ent_item = ent_item->next; } i_ipmi_set_sdr_sensors(domain, source_mc, sdr_sensors, count); if (old_sdr_sensors) { for (i=0; inext; if (ent_item->sensor) i_ipmi_sensor_put(ent_item->sensor); if (ent_item->ent) i_ipmi_entity_put(ent_item->ent); if (ent_item->mc) i_ipmi_mc_put(ent_item->mc); ipmi_mem_free(ent_item); } /* Report then free up all the new sensors. */ while (new_sensors) { ent_item = new_sensors; new_sensors = new_sensors->next; if (ent_item->ent && ent_item->sensor) ent_item->sensor->add_pending = 1; if (ent_item->sensor) i_ipmi_sensor_put(ent_item->sensor); if (ent_item->ent) i_ipmi_entity_put(ent_item->ent); if (ent_item->mc) i_ipmi_mc_put(ent_item->mc); ipmi_mem_free(ent_item); } out: /* Cleanup unused links. */ while (links) { link = links; links = link->next; locked_list_free_entry(link); } return rv; out_err: /* Release all the entities, sensors, etc. */ while (del_sensors) { ent_item = del_sensors; del_sensors = del_sensors->next; if (ent_item->sensor) i_ipmi_sensor_put(ent_item->sensor); if (ent_item->ent) i_ipmi_entity_put(ent_item->ent); if (ent_item->mc) i_ipmi_mc_put(ent_item->mc); ipmi_mem_free(ent_item); } while (new_sensors) { ent_item = new_sensors; new_sensors = new_sensors->next; if (ent_item->sensor) i_ipmi_sensor_put(ent_item->sensor); if (ent_item->ent) i_ipmi_entity_put(ent_item->ent); if (ent_item->mc) i_ipmi_mc_put(ent_item->mc); ipmi_mem_free(ent_item); } goto out; out_err_free_unlock: i_ipmi_domain_entity_unlock(domain); out_err_free: /* Free up the usecounts on all the MCs we got. */ for (i=0; imc)) i_ipmi_mc_put(nsensor->mc); } goto out_err; } /*********************************************************************** * * Get/set various local information about a sensor. * **********************************************************************/ int ipmi_sensor_get_nominal_reading(ipmi_sensor_t *sensor, double *nominal_reading) { CHECK_SENSOR_LOCK(sensor); if (!sensor->nominal_reading_specified) return ENOSYS; return (ipmi_sensor_convert_from_raw(sensor, sensor->nominal_reading, nominal_reading)); } int ipmi_sensor_get_normal_max(ipmi_sensor_t *sensor, double *normal_max) { CHECK_SENSOR_LOCK(sensor); if (!sensor->normal_max_specified) return ENOSYS; return (ipmi_sensor_convert_from_raw(sensor, sensor->normal_max, normal_max)); } int ipmi_sensor_get_normal_min(ipmi_sensor_t *sensor, double *normal_min) { CHECK_SENSOR_LOCK(sensor); if (!sensor->normal_min_specified) return ENOSYS; return (ipmi_sensor_convert_from_raw(sensor, sensor->normal_min, normal_min)); } int ipmi_sensor_get_sensor_max(ipmi_sensor_t *sensor, double *sensor_max) { CHECK_SENSOR_LOCK(sensor); return (ipmi_sensor_convert_from_raw(sensor, sensor->sensor_max, sensor_max)); } int ipmi_sensor_get_sensor_min(ipmi_sensor_t *sensor, double *sensor_min) { CHECK_SENSOR_LOCK(sensor); return (ipmi_sensor_convert_from_raw(sensor, sensor->sensor_min, sensor_min)); } int ipmi_sensor_set_raw_default_threshold(ipmi_sensor_t *sensor, int threshold, int val) { if ((threshold < 0) || (threshold > 5)) return EINVAL; sensor->default_thresholds[threshold] = val; return 0; } int ipmi_sensor_get_default_threshold_raw(ipmi_sensor_t *sensor, int threshold, int *raw) { int rv; int val; CHECK_SENSOR_LOCK(sensor); if ((threshold < 0) || (threshold > 5)) return EINVAL; rv = ipmi_sensor_threshold_settable(sensor, threshold, &val); if (rv) return rv; if (!val) return ENOSYS; if (!ipmi_sensor_get_sensor_init_thresholds(sensor)) return ENOSYS; *raw = sensor->default_thresholds[threshold]; return 0; } int ipmi_sensor_get_default_threshold_cooked(ipmi_sensor_t *sensor, int threshold, double *cooked) { int rv; int val; CHECK_SENSOR_LOCK(sensor); if ((threshold < 0) || (threshold > 5)) return EINVAL; rv = ipmi_sensor_threshold_settable(sensor, threshold, &val); if (rv) return rv; if (!val) return ENOSYS; if (!ipmi_sensor_get_sensor_init_thresholds(sensor)) return ENOSYS; return (ipmi_sensor_convert_from_raw(sensor, sensor->default_thresholds[threshold], cooked)); } ipmi_mc_t * ipmi_sensor_get_mc(ipmi_sensor_t *sensor) { return sensor->mc; } ipmi_mc_t * ipmi_sensor_get_source_mc(ipmi_sensor_t *sensor) { CHECK_SENSOR_LOCK(sensor); return sensor->source_mc; } int ipmi_sensor_get_num(ipmi_sensor_t *sensor, int *lun, int *num) { CHECK_SENSOR_LOCK(sensor); if (lun) *lun = sensor->lun; if (num) *num = sensor->num; return 0; } static void ipmi_sensor_get_event_masks(ipmi_sensor_t *sensor, uint16_t *mask1, uint16_t *mask2) { if (sensor->event_reading_type == IPMI_EVENT_READING_TYPE_THRESHOLD) { /* Remove the reading mask, as that is not part of the event values allowed. */ *mask1 = sensor->mask1 & 0x0fff; *mask2 = sensor->mask2 & 0x0fff; } else { /* Cannot set bit 15 */ *mask1 = sensor->mask1 & 0x7fff; *mask2 = sensor->mask2 & 0x7fff; } } int ipmi_sensor_threshold_event_supported(ipmi_sensor_t *sensor, enum ipmi_thresh_e event, enum ipmi_event_value_dir_e value_dir, enum ipmi_event_dir_e dir, int *val) { int idx; uint16_t mask; CHECK_SENSOR_LOCK(sensor); if (sensor->event_reading_type != IPMI_EVENT_READING_TYPE_THRESHOLD) /* Not a threshold sensor, it doesn't have readings. */ return ENOSYS; if (sensor->threshold_access == IPMI_THRESHOLD_ACCESS_SUPPORT_NONE) { /* No thresholds supported. */ *val = 0; return 0; } if (dir == IPMI_ASSERTION) mask = sensor->mask1; else if (dir == IPMI_DEASSERTION) mask = sensor->mask2; else return EINVAL; idx = (event * 2) + value_dir; if (idx > 11) return EINVAL; *val = IPMI_SENSOR_GET_MASK_BIT(mask, idx); return 0; } void ipmi_sensor_set_threshold_assertion_event_supported( ipmi_sensor_t *sensor, enum ipmi_thresh_e event, enum ipmi_event_value_dir_e dir, int val) { int idx; idx = (event * 2) + dir; if (idx > 11) return; IPMI_SENSOR_SET_MASK_BIT(sensor->mask1, idx, val); } void ipmi_sensor_set_threshold_deassertion_event_supported( ipmi_sensor_t *sensor, enum ipmi_thresh_e event, enum ipmi_event_value_dir_e dir, int val) { int idx; idx = (event * 2) + dir; if (idx > 11) return; IPMI_SENSOR_SET_MASK_BIT(sensor->mask2, idx, val); } int ipmi_sensor_threshold_reading_supported(ipmi_sensor_t *sensor, enum ipmi_thresh_e thresh, int *val) { CHECK_SENSOR_LOCK(sensor); if (sensor->event_reading_type != IPMI_EVENT_READING_TYPE_THRESHOLD) /* Not a threshold sensor, it doesn't have readings. */ return ENOSYS; switch(thresh) { case IPMI_LOWER_NON_CRITICAL: *val = IPMI_SENSOR_GET_MASK_BIT(sensor->mask1, 12); break; case IPMI_LOWER_CRITICAL: *val = IPMI_SENSOR_GET_MASK_BIT(sensor->mask1, 13); break; case IPMI_LOWER_NON_RECOVERABLE: *val = IPMI_SENSOR_GET_MASK_BIT(sensor->mask1, 14); break; case IPMI_UPPER_NON_CRITICAL: *val = IPMI_SENSOR_GET_MASK_BIT(sensor->mask2, 12); break; case IPMI_UPPER_CRITICAL: *val = IPMI_SENSOR_GET_MASK_BIT(sensor->mask2, 13); break; case IPMI_UPPER_NON_RECOVERABLE: *val = IPMI_SENSOR_GET_MASK_BIT(sensor->mask2, 14); break; default: return EINVAL; } return 0; } int ipmi_sensor_threshold_settable(ipmi_sensor_t *sensor, enum ipmi_thresh_e event, int *val) { CHECK_SENSOR_LOCK(sensor); if (sensor->event_reading_type != IPMI_EVENT_READING_TYPE_THRESHOLD) /* Not a threshold sensor, it doesn't have readings. */ return ENOSYS; if (sensor->threshold_access != IPMI_THRESHOLD_ACCESS_SUPPORT_SETTABLE) { /* Threshold setting not supported for any thresholds. */ *val = 0; return 0; } if (event > IPMI_UPPER_NON_RECOVERABLE) return EINVAL; *val = IPMI_SENSOR_GET_MASK_BIT(sensor->mask3, event + 8); return 0; } void ipmi_sensor_threshold_set_settable(ipmi_sensor_t *sensor, enum ipmi_thresh_e event, int val) { if (sensor->event_reading_type != IPMI_EVENT_READING_TYPE_THRESHOLD) /* Not a threshold sensor, it doesn't have readings. */ return; if (event > IPMI_UPPER_NON_RECOVERABLE) return; IPMI_SENSOR_SET_MASK_BIT(sensor->mask3, event + 8, val); } int ipmi_sensor_threshold_readable(ipmi_sensor_t *sensor, enum ipmi_thresh_e event, int *val) { CHECK_SENSOR_LOCK(sensor); if (sensor->event_reading_type != IPMI_EVENT_READING_TYPE_THRESHOLD) /* Not a threshold sensor, it doesn't have readings. */ return ENOSYS; if ((sensor->threshold_access == IPMI_THRESHOLD_ACCESS_SUPPORT_NONE) || (sensor->threshold_access == IPMI_THRESHOLD_ACCESS_SUPPORT_FIXED)) { /* Threshold reading not supported for any thresholds. */ *val = 0; return 0; } if (event > IPMI_UPPER_NON_RECOVERABLE) return EINVAL; *val = IPMI_SENSOR_GET_MASK_BIT(sensor->mask3, event); return 0; } void ipmi_sensor_threshold_set_readable(ipmi_sensor_t *sensor, enum ipmi_thresh_e event, int val) { if (sensor->event_reading_type != IPMI_EVENT_READING_TYPE_THRESHOLD) /* Not a threshold sensor, it doesn't have readings. */ return; if (event > IPMI_UPPER_NON_RECOVERABLE) return; IPMI_SENSOR_SET_MASK_BIT(sensor->mask3, event, val); } int ipmi_sensor_discrete_event_supported(ipmi_sensor_t *sensor, int event, enum ipmi_event_dir_e dir, int *val) { uint16_t mask; CHECK_SENSOR_LOCK(sensor); if (sensor->event_reading_type == IPMI_EVENT_READING_TYPE_THRESHOLD) /* A threshold sensor, it doesn't have events. */ return ENOSYS; if (dir == IPMI_ASSERTION) mask = sensor->mask1; else if (dir == IPMI_DEASSERTION) mask = sensor->mask2; else return EINVAL; if (event > 14) return EINVAL; *val = IPMI_SENSOR_GET_MASK_BIT(mask, event); return 0; } void ipmi_sensor_set_discrete_assertion_event_supported(ipmi_sensor_t *sensor, int event, int val) { if (event > 14) return; IPMI_SENSOR_SET_MASK_BIT(sensor->mask1, event, val); } void ipmi_sensor_set_discrete_deassertion_event_supported(ipmi_sensor_t *sensor, int event, int val) { if (event > 14) return; IPMI_SENSOR_SET_MASK_BIT(sensor->mask2, event, val); } int ipmi_sensor_discrete_event_readable(ipmi_sensor_t *sensor, int event, int *val) { CHECK_SENSOR_LOCK(sensor); if (sensor->event_reading_type == IPMI_EVENT_READING_TYPE_THRESHOLD) /* A threshold sensor, it doesn't have events. */ return ENOSYS; if (event > 14) return EINVAL; *val = IPMI_SENSOR_GET_MASK_BIT(sensor->mask3, event); return 0; } void ipmi_sensor_discrete_set_event_readable(ipmi_sensor_t *sensor, int event, int val) { if (sensor->event_reading_type == IPMI_EVENT_READING_TYPE_THRESHOLD) /* A threshold sensor, it doesn't have events. */ return; if (event > 14) return; IPMI_SENSOR_SET_MASK_BIT(sensor->mask3, event, val); } int ipmi_sensor_get_owner(ipmi_sensor_t *sensor) { CHECK_SENSOR_LOCK(sensor); return sensor->owner; } int ipmi_sensor_get_channel(ipmi_sensor_t *sensor) { CHECK_SENSOR_LOCK(sensor); return sensor->channel; } int ipmi_sensor_get_entity_id(ipmi_sensor_t *sensor) { CHECK_SENSOR_LOCK(sensor); return sensor->entity_id; } int ipmi_sensor_get_entity_instance(ipmi_sensor_t *sensor) { CHECK_SENSOR_LOCK(sensor); return sensor->entity_instance; } int ipmi_sensor_get_entity_instance_logical(ipmi_sensor_t *sensor) { CHECK_SENSOR_LOCK(sensor); return sensor->entity_instance_logical; } int ipmi_sensor_get_sensor_init_scanning(ipmi_sensor_t *sensor) { CHECK_SENSOR_LOCK(sensor); return sensor->sensor_init_scanning; } int ipmi_sensor_get_sensor_init_events(ipmi_sensor_t *sensor) { CHECK_SENSOR_LOCK(sensor); return sensor->sensor_init_events; } int ipmi_sensor_get_sensor_init_thresholds(ipmi_sensor_t *sensor) { CHECK_SENSOR_LOCK(sensor); return sensor->sensor_init_thresholds; } int ipmi_sensor_get_sensor_init_hysteresis(ipmi_sensor_t *sensor) { CHECK_SENSOR_LOCK(sensor); return sensor->sensor_init_hysteresis; } int ipmi_sensor_get_sensor_init_type(ipmi_sensor_t *sensor) { CHECK_SENSOR_LOCK(sensor); return sensor->sensor_init_type; } int ipmi_sensor_get_sensor_init_pu_events(ipmi_sensor_t *sensor) { CHECK_SENSOR_LOCK(sensor); return sensor->sensor_init_pu_events; } int ipmi_sensor_get_sensor_init_pu_scanning(ipmi_sensor_t *sensor) { CHECK_SENSOR_LOCK(sensor); return sensor->sensor_init_pu_scanning; } int ipmi_sensor_get_ignore_if_no_entity(ipmi_sensor_t *sensor) { CHECK_SENSOR_LOCK(sensor); return sensor->ignore_if_no_entity; } int ipmi_sensor_get_ignore_for_presence(ipmi_sensor_t *sensor) { CHECK_SENSOR_LOCK(sensor); return sensor->ignore_for_presence; } int ipmi_sensor_get_supports_auto_rearm(ipmi_sensor_t *sensor) { CHECK_SENSOR_LOCK(sensor); return sensor->supports_auto_rearm; } int ipmi_sensor_get_hysteresis_support(ipmi_sensor_t *sensor) { CHECK_SENSOR_LOCK(sensor); return sensor->hysteresis_support; } int ipmi_sensor_get_threshold_access(ipmi_sensor_t *sensor) { CHECK_SENSOR_LOCK(sensor); return sensor->threshold_access; } int ipmi_sensor_get_event_support(ipmi_sensor_t *sensor) { CHECK_SENSOR_LOCK(sensor); return sensor->event_support; } int ipmi_sensor_get_sensor_type(ipmi_sensor_t *sensor) { CHECK_SENSOR_LOCK(sensor); return sensor->sensor_type; } int ipmi_sensor_get_event_reading_type(ipmi_sensor_t *sensor) { CHECK_SENSOR_LOCK(sensor); return sensor->event_reading_type; } int ipmi_sensor_get_sensor_direction(ipmi_sensor_t *sensor) { CHECK_SENSOR_LOCK(sensor); return sensor->sensor_direction; } int ipmi_sensor_get_is_readable(ipmi_sensor_t *sensor) { CHECK_SENSOR_LOCK(sensor); return sensor->readable; } int ipmi_sensor_get_analog_data_format(ipmi_sensor_t *sensor) { CHECK_SENSOR_LOCK(sensor); return sensor->analog_data_format; } enum ipmi_rate_unit_e ipmi_sensor_get_rate_unit(ipmi_sensor_t *sensor) { CHECK_SENSOR_LOCK(sensor); return sensor->rate_unit; } enum ipmi_modifier_unit_use_e ipmi_sensor_get_modifier_unit_use(ipmi_sensor_t *sensor) { CHECK_SENSOR_LOCK(sensor); return sensor->modifier_unit_use; } int ipmi_sensor_get_percentage(ipmi_sensor_t *sensor) { CHECK_SENSOR_LOCK(sensor); return sensor->percentage; } enum ipmi_unit_type_e ipmi_sensor_get_base_unit(ipmi_sensor_t *sensor) { CHECK_SENSOR_LOCK(sensor); return sensor->base_unit; } enum ipmi_unit_type_e ipmi_sensor_get_modifier_unit(ipmi_sensor_t *sensor) { CHECK_SENSOR_LOCK(sensor); return sensor->modifier_unit; } int ipmi_sensor_get_linearization(ipmi_sensor_t *sensor) { CHECK_SENSOR_LOCK(sensor); return sensor->linearization; } int ipmi_sensor_get_raw_m(ipmi_sensor_t *sensor, int val) { CHECK_SENSOR_LOCK(sensor); return sensor->conv[val].m; } int ipmi_sensor_get_raw_tolerance(ipmi_sensor_t *sensor, int val) { CHECK_SENSOR_LOCK(sensor); return sensor->conv[val].tolerance; } int ipmi_sensor_get_raw_b(ipmi_sensor_t *sensor, int val) { CHECK_SENSOR_LOCK(sensor); return sensor->conv[val].b; } int ipmi_sensor_get_raw_accuracy(ipmi_sensor_t *sensor, int val) { CHECK_SENSOR_LOCK(sensor); return sensor->conv[val].accuracy; } int ipmi_sensor_get_raw_accuracy_exp(ipmi_sensor_t *sensor, int val) { CHECK_SENSOR_LOCK(sensor); return sensor->conv[val].accuracy_exp; } int ipmi_sensor_get_raw_r_exp(ipmi_sensor_t *sensor, int val) { CHECK_SENSOR_LOCK(sensor); return sensor->conv[val].r_exp; } int ipmi_sensor_get_raw_b_exp(ipmi_sensor_t *sensor, int val) { CHECK_SENSOR_LOCK(sensor); return sensor->conv[val].b_exp; } int ipmi_sensor_get_normal_min_specified(ipmi_sensor_t *sensor) { CHECK_SENSOR_LOCK(sensor); return sensor->normal_min_specified; } int ipmi_sensor_get_normal_max_specified(ipmi_sensor_t *sensor) { CHECK_SENSOR_LOCK(sensor); return sensor->normal_max_specified; } int ipmi_sensor_get_nominal_reading_specified(ipmi_sensor_t *sensor) { CHECK_SENSOR_LOCK(sensor); return sensor->nominal_reading_specified; } int ipmi_sensor_get_raw_nominal_reading(ipmi_sensor_t *sensor) { CHECK_SENSOR_LOCK(sensor); return sensor->nominal_reading; } int ipmi_sensor_get_raw_normal_max(ipmi_sensor_t *sensor) { CHECK_SENSOR_LOCK(sensor); return sensor->normal_max; } int ipmi_sensor_get_raw_normal_min(ipmi_sensor_t *sensor) { CHECK_SENSOR_LOCK(sensor); return sensor->normal_min; } int ipmi_sensor_get_raw_sensor_max(ipmi_sensor_t *sensor) { CHECK_SENSOR_LOCK(sensor); return sensor->sensor_max; } int ipmi_sensor_get_raw_sensor_min(ipmi_sensor_t *sensor) { CHECK_SENSOR_LOCK(sensor); return sensor->sensor_min; } int ipmi_sensor_get_positive_going_threshold_hysteresis(ipmi_sensor_t *sensor) { CHECK_SENSOR_LOCK(sensor); return sensor->positive_going_threshold_hysteresis; } int ipmi_sensor_get_negative_going_threshold_hysteresis(ipmi_sensor_t *sensor) { CHECK_SENSOR_LOCK(sensor); return sensor->negative_going_threshold_hysteresis; } int ipmi_sensor_get_oem1(ipmi_sensor_t *sensor) { CHECK_SENSOR_LOCK(sensor); return sensor->oem1; } int ipmi_sensor_get_id_length(ipmi_sensor_t *sensor) { CHECK_SENSOR_LOCK(sensor); if (sensor->id_type == IPMI_ASCII_STR) return sensor->id_len+1; else return sensor->id_len; } enum ipmi_str_type_e ipmi_sensor_get_id_type(ipmi_sensor_t *sensor) { CHECK_SENSOR_LOCK(sensor); return sensor->id_type; } int ipmi_sensor_get_id(ipmi_sensor_t *sensor, char *id, int length) { int clen; CHECK_SENSOR_LOCK(sensor); if ((int) sensor->id_len > length) clen = length; else clen = sensor->id_len; memcpy(id, sensor->id, clen); if (sensor->id_type == IPMI_ASCII_STR) { /* NIL terminate the ASCII string. */ if (clen == length) clen--; id[clen] = '\0'; } return clen; } void ipmi_sensor_set_owner(ipmi_sensor_t *sensor, int owner) { sensor->owner = owner; } void ipmi_sensor_set_channel(ipmi_sensor_t *sensor, int channel) { sensor->channel = channel; } void ipmi_sensor_set_entity_id(ipmi_sensor_t *sensor, int entity_id) { sensor->entity_id = entity_id; } void ipmi_sensor_set_entity_instance(ipmi_sensor_t *sensor, int entity_instance) { sensor->entity_instance = entity_instance; } void ipmi_sensor_set_entity_instance_logical(ipmi_sensor_t *sensor, int entity_instance_logical) { sensor->entity_instance_logical = entity_instance_logical; } void ipmi_sensor_set_sensor_init_scanning(ipmi_sensor_t *sensor, int sensor_init_scanning) { sensor->sensor_init_scanning = sensor_init_scanning; } void ipmi_sensor_set_sensor_init_events(ipmi_sensor_t *sensor, int sensor_init_events) { sensor->sensor_init_events = sensor_init_events; } void ipmi_sensor_set_sensor_init_thresholds(ipmi_sensor_t *sensor, int sensor_init_thresholds) { sensor->sensor_init_thresholds = sensor_init_thresholds; } void ipmi_sensor_set_sensor_init_hysteresis(ipmi_sensor_t *sensor, int sensor_init_hysteresis) { sensor->sensor_init_hysteresis = sensor_init_hysteresis; } void ipmi_sensor_set_sensor_init_type(ipmi_sensor_t *sensor, int sensor_init_type) { sensor->sensor_init_type = sensor_init_type; } void ipmi_sensor_set_sensor_init_pu_events(ipmi_sensor_t *sensor, int sensor_init_pu_events) { sensor->sensor_init_pu_events = sensor_init_pu_events; } void ipmi_sensor_set_sensor_init_pu_scanning(ipmi_sensor_t *sensor, int sensor_init_pu_scanning) { sensor->sensor_init_pu_scanning = sensor_init_pu_scanning; } void ipmi_sensor_set_ignore_if_no_entity(ipmi_sensor_t *sensor, int ignore_if_no_entity) { sensor->ignore_if_no_entity = ignore_if_no_entity; } void ipmi_sensor_set_ignore_for_presence(ipmi_sensor_t *sensor, int ignore) { sensor->ignore_for_presence = ignore; } void ipmi_sensor_set_supports_auto_rearm(ipmi_sensor_t *sensor, int val) { sensor->supports_auto_rearm = val; } void ipmi_sensor_set_hysteresis_support(ipmi_sensor_t *sensor, int hysteresis_support) { sensor->hysteresis_support = hysteresis_support; } void ipmi_sensor_set_threshold_access(ipmi_sensor_t *sensor, int threshold_access) { sensor->threshold_access = threshold_access; } void ipmi_sensor_set_event_support(ipmi_sensor_t *sensor, int event_support) { sensor->event_support = event_support; } void ipmi_sensor_set_sensor_type(ipmi_sensor_t *sensor, int sensor_type) { sensor->sensor_type = sensor_type; } void ipmi_sensor_set_event_reading_type(ipmi_sensor_t *sensor, int event_reading_type) { sensor->event_reading_type = event_reading_type; } void ipmi_sensor_set_direction(ipmi_sensor_t *sensor, int direction) { sensor->sensor_direction = direction; } void ipmi_sensor_set_is_readable(ipmi_sensor_t *sensor, int readable) { sensor->readable = readable != 0; } void ipmi_sensor_set_analog_data_format(ipmi_sensor_t *sensor, int analog_data_format) { sensor->analog_data_format = analog_data_format; } void ipmi_sensor_set_rate_unit(ipmi_sensor_t *sensor, int rate_unit) { sensor->rate_unit = rate_unit; } void ipmi_sensor_set_modifier_unit_use(ipmi_sensor_t *sensor, int modifier_unit_use) { sensor->modifier_unit_use = modifier_unit_use; } void ipmi_sensor_set_percentage(ipmi_sensor_t *sensor, int percentage) { sensor->percentage = percentage; } void ipmi_sensor_set_base_unit(ipmi_sensor_t *sensor, int base_unit) { sensor->base_unit = base_unit; } void ipmi_sensor_set_modifier_unit(ipmi_sensor_t *sensor, int modifier_unit) { sensor->modifier_unit = modifier_unit; } void ipmi_sensor_set_linearization(ipmi_sensor_t *sensor, int linearization) { sensor->linearization = linearization; } void ipmi_sensor_set_raw_m(ipmi_sensor_t *sensor, int idx, int val) { sensor->conv[idx].m = val; } void ipmi_sensor_set_raw_tolerance(ipmi_sensor_t *sensor, int idx, int val) { sensor->conv[idx].tolerance = val; } void ipmi_sensor_set_raw_b(ipmi_sensor_t *sensor, int idx, int val) { sensor->conv[idx].b = val; } void ipmi_sensor_set_raw_accuracy(ipmi_sensor_t *sensor, int idx, int val) { sensor->conv[idx].accuracy = val; } void ipmi_sensor_set_raw_accuracy_exp(ipmi_sensor_t *sensor, int idx, int val) { sensor->conv[idx].accuracy_exp = val; } void ipmi_sensor_set_raw_r_exp(ipmi_sensor_t *sensor, int idx, int val) { sensor->conv[idx].r_exp = val; } void ipmi_sensor_set_raw_b_exp(ipmi_sensor_t *sensor, int idx, int val) { sensor->conv[idx].b_exp = val; } void ipmi_sensor_set_normal_min_specified(ipmi_sensor_t *sensor, int normal_min_specified) { sensor->normal_min_specified = normal_min_specified; } void ipmi_sensor_set_normal_max_specified(ipmi_sensor_t *sensor, int normal_max_specified) { sensor->normal_max_specified = normal_max_specified; } void ipmi_sensor_set_nominal_reading_specified( ipmi_sensor_t *sensor, int nominal_reading_specified) { sensor->nominal_reading_specified = nominal_reading_specified; } void ipmi_sensor_set_raw_nominal_reading(ipmi_sensor_t *sensor, int raw_nominal_reading) { sensor->nominal_reading = raw_nominal_reading; } void ipmi_sensor_set_raw_normal_max(ipmi_sensor_t *sensor, int raw_normal_max) { sensor->normal_max = raw_normal_max; } void ipmi_sensor_set_raw_normal_min(ipmi_sensor_t *sensor, int raw_normal_min) { sensor->normal_min = raw_normal_min; } void ipmi_sensor_set_raw_sensor_max(ipmi_sensor_t *sensor, int raw_sensor_max) { sensor->sensor_max = raw_sensor_max; } void ipmi_sensor_set_raw_sensor_min(ipmi_sensor_t *sensor, int raw_sensor_min) { sensor->sensor_min = raw_sensor_min; } void ipmi_sensor_set_positive_going_threshold_hysteresis( ipmi_sensor_t *sensor, int positive_going_threshold_hysteresis) { sensor->positive_going_threshold_hysteresis = positive_going_threshold_hysteresis; } void ipmi_sensor_set_negative_going_threshold_hysteresis( ipmi_sensor_t *sensor, int negative_going_threshold_hysteresis) { sensor->negative_going_threshold_hysteresis = negative_going_threshold_hysteresis; } void ipmi_sensor_set_oem1(ipmi_sensor_t *sensor, int oem1) { sensor->oem1 = oem1; } void ipmi_sensor_set_id(ipmi_sensor_t *sensor, char *id, enum ipmi_str_type_e type, int length) { if (length > SENSOR_ID_LEN) length = SENSOR_ID_LEN; memcpy(sensor->id, id, length); sensor->id_type = type; sensor->id_len = length; if (sensor->entity) sensor_set_name(sensor); } void ipmi_sensor_set_oem_info(ipmi_sensor_t *sensor, void *oem_info, ipmi_sensor_cleanup_oem_info_cb cleanup_handler) { sensor->oem_info = oem_info; sensor->oem_info_cleanup_handler = cleanup_handler; } void * ipmi_sensor_get_oem_info(ipmi_sensor_t *sensor) { CHECK_SENSOR_LOCK(sensor); return sensor->oem_info; } const char * ipmi_sensor_get_sensor_type_string(ipmi_sensor_t *sensor) { CHECK_SENSOR_LOCK(sensor); return sensor->sensor_type_string; } void ipmi_sensor_set_sensor_type_string(ipmi_sensor_t *sensor, const char *str) { sensor->sensor_type_string = str; } const char * ipmi_sensor_get_event_reading_type_string(ipmi_sensor_t *sensor) { CHECK_SENSOR_LOCK(sensor); return sensor->event_reading_type_string; } void ipmi_sensor_set_event_reading_type_string(ipmi_sensor_t *sensor, const char *str) { sensor->event_reading_type_string = str; } const char * ipmi_sensor_get_rate_unit_string(ipmi_sensor_t *sensor) { CHECK_SENSOR_LOCK(sensor); return sensor->rate_unit_string; } void ipmi_sensor_set_rate_unit_string(ipmi_sensor_t *sensor, const char *str) { sensor->rate_unit_string = str; } const char * ipmi_sensor_get_base_unit_string(ipmi_sensor_t *sensor) { CHECK_SENSOR_LOCK(sensor); return sensor->base_unit_string; } void ipmi_sensor_set_base_unit_string(ipmi_sensor_t *sensor, const char *str) { sensor->base_unit_string = str; } const char * ipmi_sensor_get_modifier_unit_string(ipmi_sensor_t *sensor) { CHECK_SENSOR_LOCK(sensor); return sensor->modifier_unit_string; } void ipmi_sensor_set_modifier_unit_string(ipmi_sensor_t *sensor, const char *str) { sensor->modifier_unit_string = str; } void ipmi_sensor_set_hot_swap_requester(ipmi_sensor_t *sensor, int offset, int val_when_requesting) { sensor->hot_swap_requester = offset; sensor->hot_swap_requester_val = val_when_requesting; } int ipmi_sensor_is_hot_swap_requester(ipmi_sensor_t *sensor, int *offset, int *val_when_requesting) { CHECK_SENSOR_LOCK(sensor); if (sensor->hot_swap_requester != -1) { if (offset) *offset = sensor->hot_swap_requester; if (val_when_requesting) *val_when_requesting = sensor->hot_swap_requester_val; return 1; } return 0; } ipmi_domain_t * ipmi_sensor_get_domain(ipmi_sensor_t *sensor) { return sensor->domain; } ipmi_entity_t * ipmi_sensor_get_entity(ipmi_sensor_t *sensor) { return sensor->entity; } /*********************************************************************** * * Incoming event handling for sensors. * **********************************************************************/ int ipmi_sensor_threshold_set_event_handler( ipmi_sensor_t *sensor, ipmi_sensor_threshold_event_handler_nd_cb handler, void *cb_data) { CHECK_SENSOR_LOCK(sensor); sensor->threshold_event_handler = handler; sensor->cb_data = cb_data; return 0; } int ipmi_sensor_add_threshold_event_handler( ipmi_sensor_t *sensor, ipmi_sensor_threshold_event_cb handler, void *cb_data) { CHECK_SENSOR_LOCK(sensor); if (! locked_list_add(sensor->handler_list, handler, cb_data)) return ENOMEM; return 0; } int ipmi_sensor_remove_threshold_event_handler( ipmi_sensor_t *sensor, ipmi_sensor_threshold_event_cb handler, void *cb_data) { CHECK_SENSOR_LOCK(sensor); if (! locked_list_remove(sensor->handler_list, handler, cb_data)) return ENOENT; return 0; } int ipmi_sensor_add_threshold_event_handler_cl( ipmi_sensor_t *sensor, ipmi_sensor_threshold_event_cl_cb handler, void *cb_data) { CHECK_SENSOR_LOCK(sensor); if (! locked_list_add(sensor->handler_list_cl, handler, cb_data)) return ENOMEM; return 0; } int ipmi_sensor_remove_threshold_event_handler_cl( ipmi_sensor_t *sensor, ipmi_sensor_threshold_event_cl_cb handler, void *cb_data) { CHECK_SENSOR_LOCK(sensor); if (! locked_list_remove(sensor->handler_list_cl, handler, cb_data)) return ENOENT; return 0; } int ipmi_sensor_discrete_set_event_handler( ipmi_sensor_t *sensor, ipmi_sensor_discrete_event_handler_nd_cb handler, void *cb_data) { CHECK_SENSOR_LOCK(sensor); sensor->discrete_event_handler = handler; sensor->cb_data = cb_data; return 0; } int ipmi_sensor_add_discrete_event_handler( ipmi_sensor_t *sensor, ipmi_sensor_discrete_event_cb handler, void *cb_data) { CHECK_SENSOR_LOCK(sensor); if (! locked_list_add(sensor->handler_list, handler, cb_data)) return ENOMEM; return 0; } int ipmi_sensor_remove_discrete_event_handler( ipmi_sensor_t *sensor, ipmi_sensor_discrete_event_cb handler, void *cb_data) { CHECK_SENSOR_LOCK(sensor); if (! locked_list_remove(sensor->handler_list, handler, cb_data)) return ENOENT; return 0; } int ipmi_sensor_add_discrete_event_handler_cl( ipmi_sensor_t *sensor, ipmi_sensor_discrete_event_cl_cb handler, void *cb_data) { CHECK_SENSOR_LOCK(sensor); if (! locked_list_add(sensor->handler_list_cl, handler, cb_data)) return ENOMEM; return 0; } int ipmi_sensor_remove_discrete_event_handler_cl( ipmi_sensor_t *sensor, ipmi_sensor_discrete_event_cl_cb handler, void *cb_data) { CHECK_SENSOR_LOCK(sensor); if (! locked_list_remove(sensor->handler_list_cl, handler, cb_data)) return ENOENT; return 0; } typedef struct sensor_event_info_s { ipmi_sensor_t *sensor; int handled; enum ipmi_event_dir_e dir; enum ipmi_thresh_e threshold; enum ipmi_event_value_dir_e high_low; enum ipmi_value_present_e value_present; unsigned int raw_value; double value; int offset; int severity; int prev_severity; ipmi_event_t *event; } sensor_event_info_t; static int threshold_sensor_event_call_handler(void *cb_data, void *item1, void *item2) { ipmi_sensor_threshold_event_cb handler = item1; sensor_event_info_t *info = cb_data; int handled; handled = handler(info->sensor, info->dir, info->threshold, info->high_low, info->value_present, info->raw_value, info->value, item2, info->event); if (handled != IPMI_EVENT_NOT_HANDLED) { if (info->handled != IPMI_EVENT_HANDLED) /* Allow handled to override handled_pass, but not the other way. */ info->handled = handled; if (handled == IPMI_EVENT_HANDLED) info->event = NULL; } return LOCKED_LIST_ITER_CONTINUE; } void ipmi_sensor_call_threshold_event_handlers (ipmi_sensor_t *sensor, enum ipmi_event_dir_e dir, enum ipmi_thresh_e threshold, enum ipmi_event_value_dir_e high_low, enum ipmi_value_present_e value_present, unsigned int raw_value, double value, ipmi_event_t **event, int *handled) { sensor_event_info_t info; info.sensor = sensor; info.dir = dir; info.threshold = threshold; info.high_low = high_low; info.value_present = value_present; info.raw_value = raw_value; info.value = value; info.event = *event; if (handled) info.handled = *handled; else info.handled = IPMI_EVENT_NOT_HANDLED; if (sensor->threshold_event_handler) { sensor->threshold_event_handler(sensor, info.dir, info.threshold, info.high_low, info.value_present, info.raw_value, info.value, sensor->cb_data, info.event); if (info.event) info.handled = IPMI_EVENT_HANDLED; info.event = NULL; } locked_list_iterate(sensor->handler_list, threshold_sensor_event_call_handler, &info); if (handled) *handled = info.handled; *event = info.event; } static int discrete_sensor_event_call_handler(void *cb_data, void *item1, void *item2) { ipmi_sensor_discrete_event_cb handler = item1; sensor_event_info_t *info = cb_data; int handled; handled = handler(info->sensor, info->dir, info->offset, info->severity, info->prev_severity, item2, info->event); if (handled != IPMI_EVENT_NOT_HANDLED) { if (info->handled != IPMI_EVENT_HANDLED) /* Allow handled to override handled_pass, but not the other way. */ info->handled = handled; if (handled == IPMI_EVENT_HANDLED) info->event = NULL; } return LOCKED_LIST_ITER_CONTINUE; } void ipmi_sensor_call_discrete_event_handlers(ipmi_sensor_t *sensor, enum ipmi_event_dir_e dir, int offset, int severity, int prev_severity, ipmi_event_t **event, int *handled) { sensor_event_info_t info; info.sensor = sensor; info.dir = dir; info.offset = offset; info.severity = severity; info.prev_severity = prev_severity; info.event = *event; if (handled) info.handled = *handled; else info.handled = IPMI_EVENT_NOT_HANDLED; if (sensor->discrete_event_handler) { sensor->discrete_event_handler(sensor, info.dir, info.offset, info.severity, info.prev_severity, sensor->cb_data, info.event); if (info.event) info.handled = IPMI_EVENT_HANDLED; info.event = NULL; } locked_list_iterate(sensor->handler_list, discrete_sensor_event_call_handler, &info); if (handled) *handled = info.handled; *event = info.event; } int ipmi_sensor_event(ipmi_sensor_t *sensor, ipmi_event_t *event) { int rv; int handled; CHECK_SENSOR_LOCK(sensor); handled = IPMI_EVENT_NOT_HANDLED; if (sensor->event_reading_type == IPMI_EVENT_READING_TYPE_THRESHOLD) { enum ipmi_event_dir_e dir; enum ipmi_thresh_e threshold; enum ipmi_event_value_dir_e high_low; enum ipmi_value_present_e value_present; unsigned int raw_value; double value; const unsigned char *data; data = ipmi_event_get_data_ptr(event); dir = data[9] >> 7; threshold = (data[10] >> 1) & 0x07; high_low = data[10] & 1; raw_value = data[11]; value = 0.0; if ((data[10] >> 6) == 1) { rv = ipmi_sensor_convert_from_raw(sensor, raw_value, &value); if (rv) value_present = IPMI_RAW_VALUE_PRESENT; else value_present = IPMI_BOTH_VALUES_PRESENT; } else { value_present = IPMI_NO_VALUES_PRESENT; } ipmi_sensor_call_threshold_event_handlers(sensor, dir, threshold, high_low, value_present, raw_value, value, &event, &handled); } else { enum ipmi_event_dir_e dir; int offset; int severity = 0; int prev_severity = 0; const unsigned char *data; data = ipmi_event_get_data_ptr(event); dir = data[9] >> 7; offset = data[10] & 0x0f; if ((data[10] >> 6) == 2) { severity = data[11] >> 4; prev_severity = data[11] & 0xf; if (severity == 0xf) severity = -1; if (prev_severity == 0xf) prev_severity = -1; } ipmi_sensor_call_discrete_event_handlers(sensor, dir, offset, severity, prev_severity, &event, &handled); } /* Make sure the caller knows if we didn't deliver the event. */ if (handled == IPMI_EVENT_NOT_HANDLED) return EINVAL; return 0; } /*********************************************************************** * * Standard sensor messaging. * **********************************************************************/ typedef void (*sensor_done_handler_cb)(ipmi_sensor_t *sensor, int err, void *sinfo); static int sensor_done_check_rsp(ipmi_sensor_t *sensor, int err, ipmi_msg_t *rsp, unsigned int min_length, char *name, sensor_done_handler_cb done, void *sinfo) { if (err) { ipmi_log(IPMI_LOG_ERR_INFO, "%ssensor.c(%s): Got error: %x", SENSOR_NAME(sensor), name, err); done(sensor, err, sinfo); return err; } if (!sensor) { /* This *should* never happen, but we check it to shake out bugs. */ ipmi_log(IPMI_LOG_ERR_INFO, "%ssensor.c(%s): Sensor when away during operation", SENSOR_NAME(sensor), name); done(sensor, ECANCELED, sinfo); return ECANCELED; } if (rsp && rsp->data[0]) { #if 0 /* This is sometimes expected. */ ipmi_log(IPMI_LOG_ERR_INFO, "%ssensor.c(%s): Got IPMI error in response: %x", SENSOR_NAME(sensor), name, rsp->data[0]); #endif done(sensor, IPMI_IPMI_ERR_VAL(rsp->data[0]), sinfo); return IPMI_IPMI_ERR_VAL(rsp->data[0]); } if (rsp && (rsp->data_len < min_length)) { ipmi_log(IPMI_LOG_ERR_INFO, "%ssensor.c(%s): Response was too short, got %d, expected %d", SENSOR_NAME(sensor), name, rsp->data_len, min_length); done(sensor, EINVAL, sinfo); return EINVAL; } return 0; } typedef struct event_enable_info_s { ipmi_sensor_op_info_t sdata; ipmi_event_state_t state; ipmi_sensor_done_cb done; void *cb_data; int do_enable; int do_disable; } event_enable_info_t; static void enables_done_handler(ipmi_sensor_t *sensor, int err, void *sinfo) { event_enable_info_t *info = sinfo; if (info->done) info->done(sensor, err, info->cb_data); ipmi_sensor_opq_done(sensor); ipmi_mem_free(info); } static void disables_set(ipmi_sensor_t *sensor, int err, ipmi_msg_t *rsp, void *cb_data) { event_enable_info_t *info = cb_data; if (sensor_done_check_rsp(sensor, err, rsp, 1, "disables_set", enables_done_handler, info)) return; enables_done_handler(sensor, 0, info); } static void enables_set(ipmi_sensor_t *sensor, int err, ipmi_msg_t *rsp, void *cb_data) { event_enable_info_t *info = cb_data; unsigned char cmd_data[MAX_IPMI_DATA_SIZE]; ipmi_msg_t cmd_msg; int rv; if (sensor_done_check_rsp(sensor, err, rsp, 1, "enables_set", enables_done_handler, info)) return; if (info->do_disable) { /* Enables were set, now disable all the other ones. Make sure we only set event bits that we support. */ uint16_t val1, val2; cmd_msg.netfn = IPMI_SENSOR_EVENT_NETFN; cmd_msg.cmd = IPMI_SET_SENSOR_EVENT_ENABLE_CMD; cmd_msg.data_len = 6; cmd_msg.data = cmd_data; cmd_data[0] = sensor->num; cmd_data[1] = (info->state.status & 0xc0) | (0x02 << 4); ipmi_sensor_get_event_masks(sensor, &val1, &val2); val1 &= ~info->state.__assertion_events; val2 &= ~info->state.__deassertion_events; ipmi_set_uint16(cmd_data+2, val1); ipmi_set_uint16(cmd_data+4, val2); rv = ipmi_sensor_send_command(sensor, sensor->mc, sensor->send_lun, &cmd_msg, disables_set, &(info->sdata), info); if (rv) { ipmi_log(IPMI_LOG_ERR_INFO, "%ssensors.c(enables_set):" " Error sending event enable command to clear events: %x", SENSOR_NAME(sensor), rv); enables_done_handler(sensor, rv, info); } } else { /* Just doing enables, we are done. */ enables_done_handler(sensor, 0, info); } } static void event_enable_set_start(ipmi_sensor_t *sensor, int err, void *cb_data) { event_enable_info_t *info = cb_data; unsigned char cmd_data[MAX_IPMI_DATA_SIZE]; ipmi_msg_t cmd_msg; int event_support; int rv; if (sensor_done_check_rsp(sensor, err, NULL, 0, "event_enable_set_start", enables_done_handler, info)) return; event_support = ipmi_sensor_get_event_support(sensor); cmd_msg.data = cmd_data; cmd_msg.netfn = IPMI_SENSOR_EVENT_NETFN; cmd_msg.cmd = IPMI_SET_SENSOR_EVENT_ENABLE_CMD; cmd_msg.data = cmd_data; cmd_data[0] = sensor->num; if (event_support == IPMI_EVENT_SUPPORT_ENTIRE_SENSOR) { /* We can only turn on/off the entire sensor, just pass the status to the sensor. */ cmd_data[1] = info->state.status & 0xc0; cmd_msg.data_len = 2; rv = ipmi_sensor_send_command(sensor, sensor->mc, sensor->send_lun, &cmd_msg, disables_set, &(info->sdata), info); } else if (info->do_enable) { /* Start by first setting the enables, then set the disables in a second operation. We do this because enables and disables cannot both be set at the same time, and it's safer to first enable the new events then to disable the events we want disabled. It would be *really* nice if IPMI had a way to do this in one operation, such as using 11b in the request byte 2 bits 5:4 to say "set the events to exactly this state". */ cmd_data[1] = (info->state.status & 0xc0) | (0x01 << 4); cmd_data[2] = info->state.__assertion_events & 0xff; cmd_data[3] = info->state.__assertion_events >> 8; cmd_data[4] = info->state.__deassertion_events & 0xff; cmd_data[5] = info->state.__deassertion_events >> 8; cmd_msg.data_len = 6; rv = ipmi_sensor_send_command(sensor, sensor->mc, sensor->send_lun, &cmd_msg, enables_set, &(info->sdata), info); } else { /* We are only doing disables. */ cmd_data[1] = (info->state.status & 0xc0) | (0x02 << 4); cmd_data[2] = info->state.__assertion_events & 0xff; cmd_data[3] = info->state.__assertion_events >> 8; cmd_data[4] = info->state.__deassertion_events & 0xff; cmd_data[5] = info->state.__deassertion_events >> 8; cmd_msg.data_len = 6; rv = ipmi_sensor_send_command(sensor, sensor->mc, sensor->send_lun, &cmd_msg, disables_set, &(info->sdata), info); } if (rv) { ipmi_log(IPMI_LOG_ERR_INFO, "%ssensor.c(event_enable_set_start):" " Error sending event enable command: %x", SENSOR_NAME(sensor), rv); enables_done_handler(sensor, rv, info); } } static int check_events_capability(ipmi_sensor_t *sensor, ipmi_event_state_t *states) { int event_support; event_support = ipmi_sensor_get_event_support(sensor); if ((event_support == IPMI_EVENT_SUPPORT_NONE) || (event_support == IPMI_EVENT_SUPPORT_GLOBAL_ENABLE)) { /* We don't support setting events for this sensor. */ return EINVAL; } if ((event_support == IPMI_EVENT_SUPPORT_ENTIRE_SENSOR) && ((states->__assertion_events != 0) || (states->__deassertion_events != 0))) { /* This sensor does not support individual event states, but the user is trying to set them. */ return EINVAL; } if (event_support == IPMI_EVENT_SUPPORT_PER_STATE) { uint16_t mask1, mask2; ipmi_sensor_get_event_masks(sensor, &mask1, &mask2); if (((~mask1) & states->__assertion_events) || ((~mask2) & states->__deassertion_events)) { /* The user is attempting to set a state that the sensor does not support. */ return EINVAL; } } return 0; } static int stand_ipmi_sensor_set_event_enables(ipmi_sensor_t *sensor, ipmi_event_state_t *states, ipmi_sensor_done_cb done, void *cb_data) { event_enable_info_t *info; int rv; rv = check_events_capability(sensor, states); if (rv) return rv; info = ipmi_mem_alloc(sizeof(*info)); if (!info) return ENOMEM; info->state = *states; info->done = done; info->cb_data = cb_data; info->do_enable = 1; info->do_disable = 1; rv = ipmi_sensor_add_opq(sensor, event_enable_set_start, &(info->sdata), info); if (rv) ipmi_mem_free(info); return rv; } static int stand_ipmi_sensor_enable_events(ipmi_sensor_t *sensor, ipmi_event_state_t *states, ipmi_sensor_done_cb done, void *cb_data) { event_enable_info_t *info; int rv; rv = check_events_capability(sensor, states); if (rv) return rv; info = ipmi_mem_alloc(sizeof(*info)); if (!info) return ENOMEM; info->state = *states; info->done = done; info->cb_data = cb_data; info->do_enable = 1; info->do_disable = 0; rv = ipmi_sensor_add_opq(sensor, event_enable_set_start, &(info->sdata), info); if (rv) ipmi_mem_free(info); return rv; } static int stand_ipmi_sensor_disable_events(ipmi_sensor_t *sensor, ipmi_event_state_t *states, ipmi_sensor_done_cb done, void *cb_data) { event_enable_info_t *info; int rv; rv = check_events_capability(sensor, states); if (rv) return rv; info = ipmi_mem_alloc(sizeof(*info)); if (!info) return ENOMEM; info->state = *states; info->done = done; info->cb_data = cb_data; info->do_enable = 0; info->do_disable = 1; rv = ipmi_sensor_add_opq(sensor, event_enable_set_start, &(info->sdata), info); if (rv) ipmi_mem_free(info); return rv; } typedef struct event_enable_get_info_s { ipmi_sensor_op_info_t sdata; ipmi_event_state_t state; ipmi_sensor_event_enables_cb done; void *cb_data; } event_enable_get_info_t; static void enables_get_done_handler(ipmi_sensor_t *sensor, int err, void *sinfo) { event_enable_get_info_t *info = sinfo; if (info->done) info->done(sensor, err, &info->state, info->cb_data); ipmi_sensor_opq_done(sensor); ipmi_mem_free(info); } static void enables_get(ipmi_sensor_t *sensor, int err, ipmi_msg_t *rsp, void *cb_data) { event_enable_get_info_t *info = cb_data; if (sensor_done_check_rsp(sensor, err, rsp, 2, "enables_get", enables_get_done_handler, info)) return; info->state.status = rsp->data[1] & 0xc0; if (rsp->data_len >= 3) info->state.__assertion_events = rsp->data[2]; if (rsp->data_len >= 4) info->state.__assertion_events |= rsp->data[3] << 8; if (rsp->data_len >= 5) info->state.__deassertion_events = rsp->data[4]; if (rsp->data_len >= 6) info->state.__deassertion_events |= rsp->data[5] << 8; /* Mask off reserved bits */ if (sensor->event_reading_type == IPMI_EVENT_READING_TYPE_THRESHOLD) { info->state.__assertion_events &= 0x0fff; info->state.__deassertion_events &= 0x0fff; } else { info->state.__assertion_events &= 0x7fff; info->state.__deassertion_events &= 0x7fff; } /* It is possible that there are events set here that are not in sensor->mask1 (assertion events) or sensor->mask2 (deassertion events). That's a bug in the sensor; it shouldn't be setting those bits. If it ever comes to the point where we need to handle that here, a simple mask operation would do it. */ enables_get_done_handler(sensor, 0, info); } static void event_enable_get_start(ipmi_sensor_t *sensor, int err, void *cb_data) { event_enable_get_info_t *info = cb_data; unsigned char cmd_data[MAX_IPMI_DATA_SIZE]; ipmi_msg_t cmd_msg; int rv; if (sensor_done_check_rsp(sensor, err, NULL, 0, "event_enable_get_start", enables_get_done_handler, info)) return; cmd_msg.data = cmd_data; cmd_msg.netfn = IPMI_SENSOR_EVENT_NETFN; cmd_msg.cmd = IPMI_GET_SENSOR_EVENT_ENABLE_CMD; cmd_msg.data_len = 1; cmd_msg.data = cmd_data; cmd_data[0] = sensor->num; rv = ipmi_sensor_send_command(sensor, sensor->mc, sensor->send_lun, &cmd_msg, enables_get, &(info->sdata), info); if (rv) { ipmi_log(IPMI_LOG_ERR_INFO, "%ssensor.c(event_enable_get_start):" " Error sending get event enables command: %x", SENSOR_NAME(sensor), rv); enables_get_done_handler(sensor, rv, info); } } static int stand_ipmi_sensor_get_event_enables(ipmi_sensor_t *sensor, ipmi_sensor_event_enables_cb done, void *cb_data) { event_enable_get_info_t *info; int rv; info = ipmi_mem_alloc(sizeof(*info)); if (!info) return ENOMEM; memset(info, 0, sizeof(*info)); info->done = done; info->cb_data = cb_data; rv = ipmi_sensor_add_opq(sensor, event_enable_get_start, &(info->sdata), info); if (rv) ipmi_mem_free(info); return rv; } typedef struct sensor_rearm_info_s { ipmi_sensor_op_info_t sdata; ipmi_event_state_t state; int global_enable; ipmi_sensor_done_cb done; void *cb_data; } sensor_rearm_info_t; static void sensor_rearm_done_handler(ipmi_sensor_t *sensor, int err, void *sinfo) { sensor_rearm_info_t *info = sinfo; if (info->done) info->done(sensor, err, info->cb_data); ipmi_sensor_opq_done(sensor); ipmi_mem_free(info); } static void sensor_rearm(ipmi_sensor_t *sensor, int err, ipmi_msg_t *rsp, void *cb_data) { sensor_rearm_info_t *info = cb_data; if (sensor_done_check_rsp(sensor, err, rsp, 1, "sensor_rearm", sensor_rearm_done_handler, info)) return; sensor_rearm_done_handler(sensor, 0, info); } static void sensor_rearm_start(ipmi_sensor_t *sensor, int err, void *cb_data) { sensor_rearm_info_t *info = cb_data; unsigned char cmd_data[MAX_IPMI_DATA_SIZE]; ipmi_msg_t cmd_msg; int rv; if (sensor_done_check_rsp(sensor, err, NULL, 0, "sensor_rearm_start", sensor_rearm_done_handler, info)) return; cmd_msg.data = cmd_data; cmd_msg.netfn = IPMI_SENSOR_EVENT_NETFN; cmd_msg.cmd = IPMI_REARM_SENSOR_EVENTS_CMD; if (info->global_enable) { cmd_msg.data_len = 2; cmd_msg.data = cmd_data; cmd_data[0] = sensor->num; cmd_data[1] = 0; /* Rearm all events. */ } else { cmd_msg.data_len = 6; cmd_msg.data = cmd_data; cmd_data[0] = sensor->num; cmd_data[1] = 0x80; /* Rearm only specific sensors. */ cmd_data[2] = info->state.__assertion_events & 0xff; cmd_data[3] = info->state.__assertion_events >> 8; cmd_data[4] = info->state.__deassertion_events & 0xff; cmd_data[5] = info->state.__deassertion_events >> 8; } rv = ipmi_sensor_send_command(sensor, sensor->mc, sensor->send_lun, &cmd_msg, sensor_rearm, &(info->sdata), info); if (rv) { ipmi_log(IPMI_LOG_ERR_INFO, "%ssensor.c(sensor_rearm_start):" " Error sending rearm command: %x", SENSOR_NAME(sensor), rv); sensor_rearm_done_handler(sensor, rv, info); } } static int stand_ipmi_sensor_rearm(ipmi_sensor_t *sensor, int global_enable, ipmi_event_state_t *state, ipmi_sensor_done_cb done, void *cb_data) { sensor_rearm_info_t *info; int rv; if (!global_enable && !state) return EINVAL; info = ipmi_mem_alloc(sizeof(*info)); if (!info) return ENOMEM; info->done = done; info->cb_data = cb_data; info->global_enable = global_enable; if (state) memcpy(&info->state, state, sizeof(info->state)); rv = ipmi_sensor_add_opq(sensor, sensor_rearm_start, &(info->sdata), info); if (rv) ipmi_mem_free(info); return rv; } typedef struct hyst_get_info_s { ipmi_sensor_op_info_t sdata; ipmi_sensor_hysteresis_cb done; void *cb_data; unsigned int positive; unsigned int negative; } hyst_get_info_t; static void hyst_get_done_handler(ipmi_sensor_t *sensor, int err, void *sinfo) { hyst_get_info_t *info = sinfo; if (info->done) info->done(sensor, err, info->positive, info->negative, info->cb_data); ipmi_sensor_opq_done(sensor); ipmi_mem_free(info); } static void hyst_get(ipmi_sensor_t *sensor, int err, ipmi_msg_t *rsp, void *cb_data) { hyst_get_info_t *info = cb_data; if (sensor_done_check_rsp(sensor, err, rsp, 3, "hyst_get", hyst_get_done_handler, info)) return; info->positive = rsp->data[1]; info->negative = rsp->data[2]; hyst_get_done_handler(sensor, 0, info); } static void hyst_get_start(ipmi_sensor_t *sensor, int err, void *cb_data) { hyst_get_info_t *info = cb_data; unsigned char cmd_data[MAX_IPMI_DATA_SIZE]; ipmi_msg_t cmd_msg; int rv; if (sensor_done_check_rsp(sensor, err, NULL, 0, "hyst_get_start", hyst_get_done_handler, info)) return; cmd_msg.data = cmd_data; cmd_msg.netfn = IPMI_SENSOR_EVENT_NETFN; cmd_msg.cmd = IPMI_GET_SENSOR_HYSTERESIS_CMD; cmd_msg.data_len = 2; cmd_msg.data = cmd_data; cmd_data[0] = sensor->num; cmd_data[1] = 0xff; rv = ipmi_sensor_send_command(sensor, sensor->mc, sensor->send_lun, &cmd_msg, hyst_get, &(info->sdata), info); if (rv) { ipmi_log(IPMI_LOG_ERR_INFO, "%ssensor.c(hyst_get_start):" " Error sending hysteresis get command: %x", SENSOR_NAME(sensor), rv); hyst_get_done_handler(sensor, rv, info); } } static int stand_ipmi_sensor_get_hysteresis(ipmi_sensor_t *sensor, ipmi_sensor_hysteresis_cb done, void *cb_data) { hyst_get_info_t *info; int rv; if (sensor->event_reading_type != IPMI_EVENT_READING_TYPE_THRESHOLD) /* Not a threshold sensor, it doesn't have readings. */ return ENOSYS; if ((sensor->hysteresis_support != IPMI_HYSTERESIS_SUPPORT_READABLE) && (sensor->hysteresis_support != IPMI_HYSTERESIS_SUPPORT_SETTABLE)) return ENOSYS; info = ipmi_mem_alloc(sizeof(*info)); if (!info) return ENOMEM; memset(info, 0, sizeof(*info)); info->done = done; info->cb_data = cb_data; rv = ipmi_sensor_add_opq(sensor, hyst_get_start, &(info->sdata), info); if (rv) ipmi_mem_free(info); return rv; } typedef struct hyst_set_info_s { ipmi_sensor_op_info_t sdata; unsigned int positive, negative; ipmi_sensor_done_cb done; void *cb_data; } hyst_set_info_t; static void hyst_set_done_handler(ipmi_sensor_t *sensor, int err, void *sinfo) { hyst_set_info_t *info = sinfo; if (info->done) info->done(sensor, err, info->cb_data); ipmi_sensor_opq_done(sensor); ipmi_mem_free(info); } static void hyst_set(ipmi_sensor_t *sensor, int err, ipmi_msg_t *rsp, void *cb_data) { hyst_set_info_t *info = cb_data; if (sensor_done_check_rsp(sensor, err, rsp, 1, "hyst_set", hyst_set_done_handler, info)) return; hyst_set_done_handler(sensor, 0, info); } static void hyst_set_start(ipmi_sensor_t *sensor, int err, void *cb_data) { hyst_set_info_t *info = cb_data; unsigned char cmd_data[MAX_IPMI_DATA_SIZE]; ipmi_msg_t cmd_msg; int rv; if (sensor_done_check_rsp(sensor, err, NULL, 0, "hyst_set_start", hyst_set_done_handler, info)) return; cmd_msg.data = cmd_data; cmd_msg.netfn = IPMI_SENSOR_EVENT_NETFN; cmd_msg.cmd = IPMI_SET_SENSOR_HYSTERESIS_CMD; cmd_msg.data_len = 4; cmd_msg.data = cmd_data; cmd_data[0] = sensor->num; cmd_data[1] = 0xff; cmd_data[2] = info->positive; cmd_data[3] = info->negative; rv = ipmi_sensor_send_command(sensor, sensor->mc, sensor->send_lun, &cmd_msg, hyst_set, &(info->sdata), info); if (rv) { ipmi_log(IPMI_LOG_ERR_INFO, "%ssensor.c(hyst_set_start):" " Error sending hysteresis set command: %x", SENSOR_NAME(sensor), rv); hyst_set_done_handler(sensor, rv, info); } } static int stand_ipmi_sensor_set_hysteresis(ipmi_sensor_t *sensor, unsigned int positive_hysteresis, unsigned int negative_hysteresis, ipmi_sensor_done_cb done, void *cb_data) { hyst_set_info_t *info; int rv; if (sensor->event_reading_type != IPMI_EVENT_READING_TYPE_THRESHOLD) /* Not a threshold sensor, it doesn't have readings. */ return ENOSYS; if (sensor->hysteresis_support != IPMI_HYSTERESIS_SUPPORT_SETTABLE) return ENOSYS; info = ipmi_mem_alloc(sizeof(*info)); if (!info) return ENOMEM; info->positive = positive_hysteresis; info->negative = negative_hysteresis; info->done = done; info->cb_data = cb_data; rv = ipmi_sensor_add_opq(sensor, hyst_set_start, &(info->sdata), info); if (rv) ipmi_mem_free(info); return rv; } typedef struct thresh_get_info_s { ipmi_sensor_op_info_t sdata; ipmi_thresholds_t th; ipmi_sensor_thresholds_cb done; void *cb_data; } thresh_get_info_t; static void thresh_get_done_handler(ipmi_sensor_t *sensor, int err, void *sinfo) { thresh_get_info_t *info = sinfo; if (info->done) info->done(sensor, err, &info->th, info->cb_data); ipmi_sensor_opq_done(sensor); ipmi_mem_free(info); } static void thresh_get(ipmi_sensor_t *sensor, int err, ipmi_msg_t *rsp, void *cb_data) { thresh_get_info_t *info = cb_data; enum ipmi_thresh_e th; if (sensor_done_check_rsp(sensor, err, rsp, 8, "thresh_get", thresh_get_done_handler, info)) return; for (th=IPMI_LOWER_NON_CRITICAL; th<=IPMI_UPPER_NON_RECOVERABLE; th++) { int rv; if (rsp->data[1] & (1 << th)) { info->th.vals[th].status = 1; rv = ipmi_sensor_convert_from_raw(sensor, rsp->data[th+2], &(info->th.vals[th].val)); if (rv) { ipmi_log(IPMI_LOG_ERR_INFO, "%ssensor.c(thresh_get):" " Could not convert raw threshold value: %x", SENSOR_NAME(sensor), rv); thresh_get_done_handler(sensor, rv, info); return; } } else { info->th.vals[th].status = 0; } } thresh_get_done_handler(sensor, 0, info); } int ipmi_get_default_sensor_thresholds(ipmi_sensor_t *sensor, ipmi_thresholds_t *th) { enum ipmi_thresh_e thnum; int rv = 0; CHECK_SENSOR_LOCK(sensor); for (thnum = IPMI_LOWER_NON_CRITICAL; thnum <= IPMI_UPPER_NON_RECOVERABLE; thnum++) { th->vals[thnum].status = 1; rv = ipmi_sensor_convert_from_raw(sensor, sensor->default_thresholds[thnum], &(th->vals[thnum].val)); if (rv) goto out; } out: return rv; } static void thresh_get_start(ipmi_sensor_t *sensor, int err, void *cb_data) { thresh_get_info_t *info = cb_data; unsigned char cmd_data[MAX_IPMI_DATA_SIZE]; ipmi_msg_t cmd_msg; int rv; if (sensor_done_check_rsp(sensor, err, NULL, 0, "thresh_get_start", thresh_get_done_handler, info)) return; if (sensor->threshold_access == IPMI_THRESHOLD_ACCESS_SUPPORT_FIXED) { int thnum; /* Thresholds are fixed, they cannot be read. */ for (thnum = IPMI_LOWER_NON_CRITICAL; thnum <= IPMI_UPPER_NON_RECOVERABLE; thnum++) { info->th.vals[thnum].status = 0; } thresh_get_done_handler(sensor, 0, info); return; } cmd_msg.data = cmd_data; cmd_msg.netfn = IPMI_SENSOR_EVENT_NETFN; cmd_msg.cmd = IPMI_GET_SENSOR_THRESHOLD_CMD; cmd_msg.data_len = 1; cmd_msg.data = cmd_data; cmd_data[0] = sensor->num; rv = ipmi_sensor_send_command(sensor, sensor->mc, sensor->send_lun, &cmd_msg, thresh_get, &(info->sdata), info); if (rv) { ipmi_log(IPMI_LOG_ERR_INFO, "%ssensor.c(thresh_get_start):" " Error sending threshold get command: %x", SENSOR_NAME(sensor), rv); thresh_get_done_handler(sensor, rv, info); } } static int stand_ipmi_sensor_get_thresholds(ipmi_sensor_t *sensor, ipmi_sensor_thresholds_cb done, void *cb_data) { thresh_get_info_t *info; int rv; if (sensor->event_reading_type != IPMI_EVENT_READING_TYPE_THRESHOLD) /* Not a threshold sensor, it doesn't have readings. */ return ENOSYS; if (sensor->threshold_access == IPMI_THRESHOLD_ACCESS_SUPPORT_NONE) return ENOSYS; info = ipmi_mem_alloc(sizeof(*info)); if (!info) return ENOMEM; info->done = done; info->cb_data = cb_data; rv = ipmi_sensor_add_opq(sensor, thresh_get_start, &(info->sdata), info); if (rv) ipmi_mem_free(info); return rv; } typedef struct thresh_set_info_s { ipmi_sensor_op_info_t sdata; ipmi_thresholds_t th; ipmi_sensor_done_cb done; void *cb_data; } thresh_set_info_t; static void thresh_set_done_handler(ipmi_sensor_t *sensor, int err, void *sinfo) { thresh_set_info_t *info = sinfo; if (info->done) info->done(sensor, err, info->cb_data); ipmi_sensor_opq_done(sensor); ipmi_mem_free(info); } static void thresh_set(ipmi_sensor_t *sensor, int err, ipmi_msg_t *rsp, void *cb_data) { thresh_set_info_t *info = cb_data; if (sensor_done_check_rsp(sensor, err, rsp, 1, "thresh_set", thresh_set_done_handler, info)) return; thresh_set_done_handler(sensor, 0, info); } static void thresh_set_start(ipmi_sensor_t *sensor, int err, void *cb_data) { thresh_set_info_t *info = cb_data; unsigned char cmd_data[MAX_IPMI_DATA_SIZE]; ipmi_msg_t cmd_msg; int rv; enum ipmi_thresh_e th; if (sensor_done_check_rsp(sensor, err, NULL, 0, "thresh_set_start", thresh_set_done_handler, info)) return; cmd_msg.data = cmd_data; cmd_msg.netfn = IPMI_SENSOR_EVENT_NETFN; cmd_msg.cmd = IPMI_SET_SENSOR_THRESHOLD_CMD; cmd_msg.data_len = 8; cmd_msg.data = cmd_data; cmd_data[0] = sensor->num; cmd_data[1] = 0; for (th=IPMI_LOWER_NON_CRITICAL; th<=IPMI_UPPER_NON_RECOVERABLE; th++) { int val; if (info->th.vals[th].status) { cmd_data[1] |= (1 << th); rv = ipmi_sensor_convert_to_raw(sensor, ROUND_NORMAL, info->th.vals[th].val, &val); if (rv) { ipmi_log(IPMI_LOG_ERR_INFO, "%ssensor.c(thresh_set_start):" "Error converting threshold to raw: %x", SENSOR_NAME(sensor), rv); thresh_set_done_handler(sensor, rv, info); return; } } else { val = 0; } cmd_data[th+2] = val; } rv = ipmi_sensor_send_command(sensor, sensor->mc, sensor->send_lun, &cmd_msg, thresh_set, &(info->sdata), info); if (rv) { ipmi_log(IPMI_LOG_ERR_INFO, "%ssensor.c(thresh_set_start):" "Error sending thresholds set command: %x", SENSOR_NAME(sensor), rv); thresh_set_done_handler(sensor, rv, info); } } static int stand_ipmi_sensor_set_thresholds(ipmi_sensor_t *sensor, ipmi_thresholds_t *thresholds, ipmi_sensor_done_cb done, void *cb_data) { thresh_set_info_t *info; int rv; if (sensor->event_reading_type != IPMI_EVENT_READING_TYPE_THRESHOLD) /* Not a threshold sensor, it doesn't have readings. */ return ENOSYS; if (sensor->threshold_access != IPMI_THRESHOLD_ACCESS_SUPPORT_SETTABLE) return ENOSYS; info = ipmi_mem_alloc(sizeof(*info)); if (!info) return ENOMEM; info->th = *thresholds; info->done = done; info->cb_data = cb_data; rv = ipmi_sensor_add_opq(sensor, thresh_set_start, &(info->sdata), info); if (rv) ipmi_mem_free(info); return rv; } typedef struct reading_get_info_s { ipmi_sensor_op_info_t sdata; ipmi_sensor_reading_cb done; void *cb_data; ipmi_states_t states; enum ipmi_value_present_e value_present; unsigned int raw_val; double cooked_val; } reading_get_info_t; static void reading_get_done_handler(ipmi_sensor_t *sensor, int err, void *sinfo) { reading_get_info_t *info = sinfo; if (info->done) info->done(sensor, err, info->value_present, info->raw_val, info->cooked_val, &info->states, info->cb_data); ipmi_sensor_opq_done(sensor); ipmi_mem_free(info); } static void reading_get(ipmi_sensor_t *sensor, int err, ipmi_msg_t *rsp, void *rsp_data) { reading_get_info_t *info = rsp_data; int rv; if (sensor_done_check_rsp(sensor, err, rsp, 3, "reading_get", reading_get_done_handler, info)) return; info->raw_val = rsp->data[1]; if (sensor->analog_data_format != IPMI_ANALOG_DATA_FORMAT_NOT_ANALOG) { rv = ipmi_sensor_convert_from_raw(sensor, info->raw_val, &info->cooked_val); if (rv) info->value_present = IPMI_RAW_VALUE_PRESENT; else info->value_present = IPMI_BOTH_VALUES_PRESENT; } else { info->value_present = IPMI_NO_VALUES_PRESENT; } info->states.__event_messages_enabled = (rsp->data[2] >> 7) & 1; info->states.__sensor_scanning_enabled = (rsp->data[2] >> 6) & 1; info->states.__initial_update_in_progress = (rsp->data[2] >> 5) & 1; if (rsp->data_len >= 4) info->states.__states = rsp->data[3]; reading_get_done_handler(sensor, 0, info); } static void reading_get_start(ipmi_sensor_t *sensor, int err, void *cb_data) { reading_get_info_t *info = cb_data; unsigned char cmd_data[MAX_IPMI_DATA_SIZE]; ipmi_msg_t cmd_msg; int rv; if (sensor_done_check_rsp(sensor, err, NULL, 0, "reading_get_start", reading_get_done_handler, info)) return; cmd_msg.data = cmd_data; cmd_msg.netfn = IPMI_SENSOR_EVENT_NETFN; cmd_msg.cmd = IPMI_GET_SENSOR_READING_CMD; cmd_msg.data_len = 1; cmd_msg.data = cmd_data; cmd_data[0] = sensor->num; rv = ipmi_sensor_send_command(sensor, sensor->mc, sensor->send_lun, &cmd_msg, reading_get, &(info->sdata), info); if (rv) { ipmi_log(IPMI_LOG_ERR_INFO, "%ssensor.c(reading_get_start):" "Error sending reading get command: %x", SENSOR_NAME(sensor), rv); reading_get_done_handler(sensor, rv, info); } } static int stand_ipmi_sensor_get_reading(ipmi_sensor_t *sensor, ipmi_sensor_reading_cb done, void *cb_data) { reading_get_info_t *info; int rv; if (sensor->event_reading_type != IPMI_EVENT_READING_TYPE_THRESHOLD) /* Not a threshold sensor, it doesn't have readings. */ return ENOSYS; if (!sensor->readable) return ENOSYS; info = ipmi_mem_alloc(sizeof(*info)); if (!info) return ENOMEM; info->done = done; info->cb_data = cb_data; info->value_present = IPMI_NO_VALUES_PRESENT; info->raw_val = 0; info->cooked_val = 0.0; ipmi_init_states(&info->states); rv = ipmi_sensor_add_opq(sensor, reading_get_start, &(info->sdata), info); if (rv) ipmi_mem_free(info); return rv; } typedef struct states_get_info_s { ipmi_sensor_op_info_t sdata; ipmi_sensor_states_cb done; void *cb_data; ipmi_states_t states; } states_get_info_t; static void states_get_done_handler(ipmi_sensor_t *sensor, int err, void *sinfo) { states_get_info_t *info = sinfo; if (info->done) info->done(sensor, err, &info->states, info->cb_data); ipmi_sensor_opq_done(sensor); ipmi_mem_free(info); } static void states_get(ipmi_sensor_t *sensor, int err, ipmi_msg_t *rsp, void *cb_data) { states_get_info_t *info = cb_data; if (sensor_done_check_rsp(sensor, err, rsp, 3, "states_get", states_get_done_handler, info)) return; info->states.__event_messages_enabled = (rsp->data[2] >> 7) & 1; info->states.__sensor_scanning_enabled = (rsp->data[2] >> 6) & 1; info->states.__initial_update_in_progress = (rsp->data[2] >> 5) & 1; if (rsp->data_len >= 4) info->states.__states |= rsp->data[3]; if (rsp->data_len >= 5) info->states.__states |= rsp->data[4] << 8; states_get_done_handler(sensor, 0, info); } static void states_get_start(ipmi_sensor_t *sensor, int err, void *cb_data) { states_get_info_t *info = cb_data; unsigned char cmd_data[MAX_IPMI_DATA_SIZE]; ipmi_msg_t cmd_msg; int rv; if (sensor_done_check_rsp(sensor, err, NULL, 0, "states_get_start", states_get_done_handler, info)) return; cmd_msg.data = cmd_data; cmd_msg.netfn = IPMI_SENSOR_EVENT_NETFN; cmd_msg.cmd = IPMI_GET_SENSOR_READING_CMD; cmd_msg.data_len = 1; cmd_msg.data = cmd_data; cmd_data[0] = sensor->num; rv = ipmi_sensor_send_command(sensor, sensor->mc, sensor->send_lun, &cmd_msg, states_get, &(info->sdata), info); if (rv) { ipmi_log(IPMI_LOG_ERR_INFO, "%sstates.c(states_get_start):" " Error sending states get command: %x", SENSOR_NAME(sensor), rv); states_get_done_handler(sensor, rv, info); } } static int stand_ipmi_sensor_get_states(ipmi_sensor_t *sensor, ipmi_sensor_states_cb done, void *cb_data) { states_get_info_t *info; int rv; if (sensor->event_reading_type == IPMI_EVENT_READING_TYPE_THRESHOLD) /* A threshold sensor, it doesn't have states. */ return ENOSYS; if (!sensor->readable) return ENOSYS; info = ipmi_mem_alloc(sizeof(*info)); if (!info) return ENOMEM; info->done = done; info->cb_data = cb_data; ipmi_init_states(&info->states); rv = ipmi_sensor_add_opq(sensor, states_get_start, &(info->sdata), info); if (rv) ipmi_mem_free(info); return rv; } /*********************************************************************** * * Various data conversion stuff. * **********************************************************************/ static double c_linear(double val) { return val; } static double c_log2(double val) { return log(val) / 0.69314718 /* log(2) */; } static double c_exp10(double val) { return pow(10.0, val); } static double c_exp2(double val) { return pow(2.0, val); } static double c_1_over_x(double val) { return 1.0 / val; } static double c_sqr(double val) { return pow(val, 2.0); } static double c_cube(double val) { return pow(val, 3.0); } static double c_1_over_cube(double val) { return 1.0 / pow(val, 3.0); } typedef double (*linearizer)(double val); static linearizer linearize[12] = { c_linear, log, log10, c_log2, exp, c_exp10, c_exp2, c_1_over_x, c_sqr, c_cube, sqrt, c_1_over_cube }; static int sign_extend(int m, int bits) { if (m & (1 << (bits-1))) return m | (-1 << bits); else return m & (~(-1 << bits)); } static int stand_ipmi_sensor_convert_from_raw(ipmi_sensor_t *sensor, int val, double *result) { double m, b, b_exp, r_exp, fval; linearizer c_func; if (sensor->event_reading_type != IPMI_EVENT_READING_TYPE_THRESHOLD) /* Not a threshold sensor, it doesn't have readings. */ return ENOSYS; if (sensor->linearization == IPMI_LINEARIZATION_NONLINEAR) c_func = c_linear; else if (sensor->linearization <= 11) c_func = linearize[sensor->linearization]; else return EINVAL; val &= 0xff; m = sensor->conv[val].m; b = sensor->conv[val].b; r_exp = sensor->conv[val].r_exp; b_exp = sensor->conv[val].b_exp; switch(sensor->analog_data_format) { case IPMI_ANALOG_DATA_FORMAT_UNSIGNED: fval = val; break; case IPMI_ANALOG_DATA_FORMAT_1_COMPL: val = sign_extend(val, 8); if (val < 0) val += 1; fval = val; break; case IPMI_ANALOG_DATA_FORMAT_2_COMPL: fval = sign_extend(val, 8); break; default: return EINVAL; } *result = c_func(((m * fval) + (b * pow(10, b_exp))) * pow(10, r_exp)); return 0; } static int stand_ipmi_sensor_convert_to_raw(ipmi_sensor_t *sensor, enum ipmi_round_e rounding, double val, int *result) { double cval; int lowraw, highraw, raw, maxraw, minraw, next_raw; int rv; if (sensor->event_reading_type != IPMI_EVENT_READING_TYPE_THRESHOLD) /* Not a threshold sensor, it doesn't have readings. */ return ENOSYS; switch(sensor->analog_data_format) { case IPMI_ANALOG_DATA_FORMAT_UNSIGNED: lowraw = 0; highraw = 255; minraw = 0; maxraw = 255; next_raw = 128; break; case IPMI_ANALOG_DATA_FORMAT_1_COMPL: lowraw = -127; highraw = 127; minraw = -127; maxraw = 127; next_raw = 0; break; case IPMI_ANALOG_DATA_FORMAT_2_COMPL: lowraw = -128; highraw = 127; minraw = -128; maxraw = 127; next_raw = 0; break; default: return EINVAL; } /* We do a binary search for the right value. Yuck, but I don't have a better plan that will work with non-linear sensors. */ do { raw = next_raw; rv = ipmi_sensor_convert_from_raw(sensor, raw, &cval); if (rv) return rv; if (cval < val) { next_raw = ((highraw - raw) / 2) + raw; lowraw = raw; } else { next_raw = ((raw - lowraw) / 2) + lowraw; highraw = raw; } } while (raw != next_raw); /* The above loop gets us to within 1 of what it should be, we have to look at rounding to make the final decision. */ switch (rounding) { case ROUND_NORMAL: if (val > cval) { if (raw < maxraw) { double nval; rv = ipmi_sensor_convert_from_raw(sensor, raw+1, &nval); if (rv) return rv; nval = cval + ((nval - cval) / 2.0); if (val >= nval) raw++; } } else { if (raw > minraw) { double pval; rv = ipmi_sensor_convert_from_raw(sensor, raw-1, &pval); if (rv) return rv; pval = pval + ((cval - pval) / 2.0); if (val < pval) raw--; } } break; case ROUND_UP: if ((val > cval) && (raw < maxraw)) { raw++; } break; case ROUND_DOWN: if ((val < cval) && (raw > minraw)) { raw--; } break; } if (sensor->analog_data_format == IPMI_ANALOG_DATA_FORMAT_1_COMPL) { if (raw < 0) raw -= 1; } *result = raw & 0xff; return 0; } static int stand_ipmi_sensor_get_tolerance(ipmi_sensor_t *sensor, int val, double *tolerance) { double m, r_exp, fval; linearizer c_func; if (sensor->event_reading_type != IPMI_EVENT_READING_TYPE_THRESHOLD) /* Not a threshold sensor, it doesn't have readings. */ return ENOSYS; if (sensor->linearization == IPMI_LINEARIZATION_NONLINEAR) c_func = c_linear; else if (sensor->linearization <= 11) c_func = linearize[sensor->linearization]; else return EINVAL; val &= 0xff; m = sensor->conv[val].m; r_exp = sensor->conv[val].r_exp; fval = sign_extend(val, 8); *tolerance = c_func(((m * fval) / 2.0) * pow(10, r_exp)); return 0; } /* Returns accuracy as a percentage value. */ static int stand_ipmi_sensor_get_accuracy(ipmi_sensor_t *sensor, int val, double *accuracy) { double a, a_exp; if (sensor->event_reading_type != IPMI_EVENT_READING_TYPE_THRESHOLD) /* Not a threshold sensor, it doesn't have readings. */ return ENOSYS; val &= 0xff; a = sensor->conv[val].accuracy; a_exp = sensor->conv[val].r_exp; *accuracy = (a * pow(10, a_exp)) / 100.0; return 0; } static const char * stand_ipmi_sensor_reading_name_string(ipmi_sensor_t *sensor, int offset) { return ipmi_get_reading_name(sensor->event_reading_type, sensor->sensor_type, offset); } /*********************************************************************** * * The standard callback structure * **********************************************************************/ const ipmi_sensor_cbs_t ipmi_standard_sensor_cb = { .ipmi_sensor_set_event_enables = stand_ipmi_sensor_set_event_enables, .ipmi_sensor_get_event_enables = stand_ipmi_sensor_get_event_enables, .ipmi_sensor_enable_events = stand_ipmi_sensor_enable_events, .ipmi_sensor_disable_events = stand_ipmi_sensor_disable_events, .ipmi_sensor_rearm = stand_ipmi_sensor_rearm, .ipmi_sensor_convert_from_raw = stand_ipmi_sensor_convert_from_raw, .ipmi_sensor_convert_to_raw = stand_ipmi_sensor_convert_to_raw, .ipmi_sensor_get_accuracy = stand_ipmi_sensor_get_accuracy, .ipmi_sensor_get_tolerance = stand_ipmi_sensor_get_tolerance, .ipmi_sensor_get_hysteresis = stand_ipmi_sensor_get_hysteresis, .ipmi_sensor_set_hysteresis = stand_ipmi_sensor_set_hysteresis, .ipmi_sensor_set_thresholds = stand_ipmi_sensor_set_thresholds, .ipmi_sensor_get_thresholds = stand_ipmi_sensor_get_thresholds, .ipmi_sensor_get_reading = stand_ipmi_sensor_get_reading, .ipmi_sensor_get_states = stand_ipmi_sensor_get_states, .ipmi_sensor_reading_name_string = stand_ipmi_sensor_reading_name_string, }; void ipmi_sensor_get_callbacks(ipmi_sensor_t *sensor, ipmi_sensor_cbs_t *cbs) { *cbs = sensor->cbs; } void ipmi_sensor_set_callbacks(ipmi_sensor_t *sensor, ipmi_sensor_cbs_t *cbs) { sensor->cbs = *cbs; } /*********************************************************************** * * Polymorphic calls to the callback handlers. * **********************************************************************/ int ipmi_sensor_set_event_enables(ipmi_sensor_t *sensor, ipmi_event_state_t *states, ipmi_sensor_done_cb done, void *cb_data) { if (!sensor_ok_to_use(sensor)) return ECANCELED; CHECK_SENSOR_LOCK(sensor); if (!sensor->cbs.ipmi_sensor_set_event_enables) return ENOSYS; return sensor->cbs.ipmi_sensor_set_event_enables(sensor, states, done, cb_data); } int ipmi_sensor_enable_events(ipmi_sensor_t *sensor, ipmi_event_state_t *states, ipmi_sensor_done_cb done, void *cb_data) { if (!sensor_ok_to_use(sensor)) return ECANCELED; CHECK_SENSOR_LOCK(sensor); if (!sensor->cbs.ipmi_sensor_enable_events) return ENOSYS; return sensor->cbs.ipmi_sensor_enable_events(sensor, states, done, cb_data); } int ipmi_sensor_disable_events(ipmi_sensor_t *sensor, ipmi_event_state_t *states, ipmi_sensor_done_cb done, void *cb_data) { if (!sensor_ok_to_use(sensor)) return ECANCELED; CHECK_SENSOR_LOCK(sensor); if (!sensor->cbs.ipmi_sensor_disable_events) return ENOSYS; return sensor->cbs.ipmi_sensor_disable_events(sensor, states, done, cb_data); } int ipmi_sensor_rearm(ipmi_sensor_t *sensor, int global_enable, ipmi_event_state_t *state, ipmi_sensor_done_cb done, void *cb_data) { if (!sensor_ok_to_use(sensor)) return ECANCELED; CHECK_SENSOR_LOCK(sensor); if (!sensor->cbs.ipmi_sensor_rearm) return ENOSYS; return sensor->cbs.ipmi_sensor_rearm(sensor, global_enable, state, done, cb_data); } int ipmi_sensor_get_event_enables(ipmi_sensor_t *sensor, ipmi_sensor_event_enables_cb done, void *cb_data) { if (!sensor_ok_to_use(sensor)) return ECANCELED; CHECK_SENSOR_LOCK(sensor); if (!sensor->cbs.ipmi_sensor_get_event_enables) return ENOSYS; return sensor->cbs.ipmi_sensor_get_event_enables(sensor, done, cb_data); } int ipmi_sensor_get_hysteresis(ipmi_sensor_t *sensor, ipmi_sensor_hysteresis_cb done, void *cb_data) { if (!sensor_ok_to_use(sensor)) return ECANCELED; CHECK_SENSOR_LOCK(sensor); if (!sensor->cbs.ipmi_sensor_get_hysteresis) return ENOSYS; return sensor->cbs.ipmi_sensor_get_hysteresis(sensor, done, cb_data); } int ipmi_sensor_set_hysteresis(ipmi_sensor_t *sensor, unsigned int positive_hysteresis, unsigned int negative_hysteresis, ipmi_sensor_done_cb done, void *cb_data) { if (!sensor_ok_to_use(sensor)) return ECANCELED; CHECK_SENSOR_LOCK(sensor); if (!sensor->cbs.ipmi_sensor_set_hysteresis) return ENOSYS; return sensor->cbs.ipmi_sensor_set_hysteresis(sensor, positive_hysteresis, negative_hysteresis, done, cb_data); } int ipmi_sensor_get_thresholds(ipmi_sensor_t *sensor, ipmi_sensor_thresholds_cb done, void *cb_data) { if (!sensor_ok_to_use(sensor)) return ECANCELED; CHECK_SENSOR_LOCK(sensor); if (!sensor->cbs.ipmi_sensor_get_thresholds) return ENOSYS; return sensor->cbs.ipmi_sensor_get_thresholds(sensor, done, cb_data); } int ipmi_sensor_set_thresholds(ipmi_sensor_t *sensor, ipmi_thresholds_t *thresholds, ipmi_sensor_done_cb done, void *cb_data) { if (!sensor_ok_to_use(sensor)) return ECANCELED; CHECK_SENSOR_LOCK(sensor); if (!sensor->cbs.ipmi_sensor_set_thresholds) return ENOSYS; return sensor->cbs.ipmi_sensor_set_thresholds(sensor, thresholds, done, cb_data); } int ipmi_sensor_get_reading(ipmi_sensor_t *sensor, ipmi_sensor_reading_cb done, void *cb_data) { if (!sensor_ok_to_use(sensor)) return ECANCELED; CHECK_SENSOR_LOCK(sensor); if (!sensor->cbs.ipmi_sensor_get_reading) return ENOSYS; return sensor->cbs.ipmi_sensor_get_reading(sensor, done, cb_data); } int ipmi_sensor_get_states(ipmi_sensor_t *sensor, ipmi_sensor_states_cb done, void *cb_data) { if (!sensor_ok_to_use(sensor)) return ECANCELED; CHECK_SENSOR_LOCK(sensor); if (!sensor->cbs.ipmi_sensor_get_states) return ENOSYS; return sensor->cbs.ipmi_sensor_get_states(sensor, done, cb_data); } const char * ipmi_sensor_reading_name_string(ipmi_sensor_t *sensor, int offset) { CHECK_SENSOR_LOCK(sensor); if (!sensor->cbs.ipmi_sensor_reading_name_string) return NULL; return sensor->cbs.ipmi_sensor_reading_name_string(sensor, offset); } int ipmi_sensor_convert_from_raw(ipmi_sensor_t *sensor, int val, double *result) { CHECK_SENSOR_LOCK(sensor); if (!sensor->cbs.ipmi_sensor_convert_from_raw) return ENOSYS; return sensor->cbs.ipmi_sensor_convert_from_raw(sensor, val, result); } int ipmi_sensor_convert_to_raw(ipmi_sensor_t *sensor, enum ipmi_round_e rounding, double val, int *result) { CHECK_SENSOR_LOCK(sensor); if (!sensor->cbs.ipmi_sensor_convert_to_raw) return ENOSYS; return sensor->cbs.ipmi_sensor_convert_to_raw(sensor, rounding, val, result); } int ipmi_sensor_get_tolerance(ipmi_sensor_t *sensor, int val, double *tolerance) { CHECK_SENSOR_LOCK(sensor); if (!sensor->cbs.ipmi_sensor_get_tolerance) return ENOSYS; return sensor->cbs.ipmi_sensor_get_tolerance(sensor, val, tolerance); } /* Returns accuracy as a percentage value. */ int ipmi_sensor_get_accuracy(ipmi_sensor_t *sensor, int val, double *accuracy) { CHECK_SENSOR_LOCK(sensor); if (!sensor->cbs.ipmi_sensor_get_accuracy) return ENOSYS; return sensor->cbs.ipmi_sensor_get_accuracy(sensor, val, accuracy); } /*********************************************************************** * * Convenience functions that take ids. * **********************************************************************/ typedef struct sensor_id_events_enable_set_s { ipmi_event_state_t *states; ipmi_sensor_done_cb done; void *cb_data; int rv; } sensor_id_events_enable_set_t; static void sensor_id_set_event_enables_cb(ipmi_sensor_t *sensor, void *cb_data) { sensor_id_events_enable_set_t *info = cb_data; info->rv = ipmi_sensor_set_event_enables(sensor, info->states, info->done, info->cb_data); } int ipmi_sensor_id_set_event_enables(ipmi_sensor_id_t sensor_id, ipmi_event_state_t *states, ipmi_sensor_done_cb done, void *cb_data) { sensor_id_events_enable_set_t info; int rv; info.states = states; info.done = done; info.cb_data = cb_data; rv = ipmi_sensor_pointer_cb(sensor_id, sensor_id_set_event_enables_cb, &info); if (!rv) rv = info.rv; return rv; } typedef struct sensor_id_events_enable_s { ipmi_event_state_t *states; ipmi_sensor_done_cb done; void *cb_data; int rv; } sensor_id_events_enable_t; static void sensor_id_enable_events_cb(ipmi_sensor_t *sensor, void *cb_data) { sensor_id_events_enable_t *info = cb_data; info->rv = ipmi_sensor_enable_events(sensor, info->states, info->done, info->cb_data); } int ipmi_sensor_id_enable_events(ipmi_sensor_id_t sensor_id, ipmi_event_state_t *states, ipmi_sensor_done_cb done, void *cb_data) { sensor_id_events_enable_t info; int rv; info.states = states; info.done = done; info.cb_data = cb_data; rv = ipmi_sensor_pointer_cb(sensor_id, sensor_id_enable_events_cb, &info); if (!rv) rv = info.rv; return rv; } typedef struct sensor_id_events_disable_s { ipmi_event_state_t *states; ipmi_sensor_done_cb done; void *cb_data; int rv; } sensor_id_events_disable_t; static void sensor_id_disable_events_cb(ipmi_sensor_t *sensor, void *cb_data) { sensor_id_events_disable_t *info = cb_data; info->rv = ipmi_sensor_disable_events(sensor, info->states, info->done, info->cb_data); } int ipmi_sensor_id_disable_events(ipmi_sensor_id_t sensor_id, ipmi_event_state_t *states, ipmi_sensor_done_cb done, void *cb_data) { sensor_id_events_enable_t info; int rv; info.states = states; info.done = done; info.cb_data = cb_data; rv = ipmi_sensor_pointer_cb(sensor_id, sensor_id_disable_events_cb, &info); if (!rv) rv = info.rv; return rv; } typedef struct sensor_id_events_enable_get_s { ipmi_sensor_event_enables_cb done; void *cb_data; int rv; } sensor_id_events_enable_get_t; static void sensor_id_get_event_enables_cb(ipmi_sensor_t *sensor, void *cb_data) { sensor_id_events_enable_get_t *info = cb_data; info->rv = ipmi_sensor_get_event_enables(sensor, info->done, info->cb_data); } int ipmi_sensor_id_get_event_enables(ipmi_sensor_id_t sensor_id, ipmi_sensor_event_enables_cb done, void *cb_data) { sensor_id_events_enable_get_t info; int rv; info.done = done; info.cb_data = cb_data; rv = ipmi_sensor_pointer_cb(sensor_id, sensor_id_get_event_enables_cb, &info); if (!rv) rv = info.rv; return rv; } typedef struct sensor_id_rearm_s { int global_enable; ipmi_event_state_t *state; ipmi_sensor_done_cb done; void *cb_data; int rv; } sensor_id_rearm_t; static void sensor_id_rearm_cb(ipmi_sensor_t *sensor, void *cb_data) { sensor_id_rearm_t *info = cb_data; info->rv = ipmi_sensor_rearm(sensor, info->global_enable, info->state, info->done, info->cb_data); } int ipmi_sensor_id_rearm(ipmi_sensor_id_t sensor_id, int global_enable, ipmi_event_state_t *state, ipmi_sensor_done_cb done, void *cb_data) { sensor_id_rearm_t info; int rv; info.global_enable = global_enable; info.state = state; info.done = done; info.cb_data = cb_data; rv = ipmi_sensor_pointer_cb(sensor_id, sensor_id_rearm_cb, &info); if (!rv) rv = info.rv; return rv; } typedef struct sensor_id_get_hysteresis_s { ipmi_sensor_hysteresis_cb done; void *cb_data; int rv; } sensor_id_get_hysteresis_t; static void sensor_id_get_hysteresis_cb(ipmi_sensor_t *sensor, void *cb_data) { sensor_id_get_hysteresis_t *info = cb_data; info->rv = ipmi_sensor_get_hysteresis(sensor, info->done, info->cb_data); } int ipmi_sensor_id_get_hysteresis(ipmi_sensor_id_t sensor_id, ipmi_sensor_hysteresis_cb done, void *cb_data) { sensor_id_get_hysteresis_t info; int rv; info.done = done; info.cb_data = cb_data; rv = ipmi_sensor_pointer_cb(sensor_id, sensor_id_get_hysteresis_cb, &info); if (!rv) rv = info.rv; return rv; } typedef struct sensor_id_set_hysteresis_s { unsigned int positive_hysteresis; unsigned int negative_hysteresis; ipmi_sensor_done_cb done; void *cb_data; int rv; } sensor_id_set_hysteresis_t; static void sensor_id_set_hysteresis_cb(ipmi_sensor_t *sensor, void *cb_data) { sensor_id_set_hysteresis_t *info = cb_data; info->rv = ipmi_sensor_set_hysteresis(sensor, info->positive_hysteresis, info->negative_hysteresis, info->done, info->cb_data); } int ipmi_sensor_id_set_hysteresis(ipmi_sensor_id_t sensor_id, unsigned int positive_hysteresis, unsigned int negative_hysteresis, ipmi_sensor_done_cb done, void *cb_data) { sensor_id_set_hysteresis_t info; int rv; info.positive_hysteresis = positive_hysteresis; info.negative_hysteresis = negative_hysteresis; info.done = done; info.cb_data = cb_data; rv = ipmi_sensor_pointer_cb(sensor_id, sensor_id_set_hysteresis_cb, &info); if (!rv) rv = info.rv; return rv; } typedef struct sensor_id_thresholds_set_s { ipmi_thresholds_t *thresholds; ipmi_sensor_done_cb done; void *cb_data; int rv; } sensor_id_thresholds_set_t; static void sensor_id_set_thresholds_cb(ipmi_sensor_t *sensor, void *cb_data) { sensor_id_thresholds_set_t *info = cb_data; info->rv = ipmi_sensor_set_thresholds(sensor, info->thresholds, info->done, info->cb_data); } int ipmi_sensor_id_set_thresholds(ipmi_sensor_id_t sensor_id, ipmi_thresholds_t *thresholds, ipmi_sensor_done_cb done, void *cb_data) { sensor_id_thresholds_set_t info; int rv; info.thresholds = thresholds; info.done = done; info.cb_data = cb_data; rv = ipmi_sensor_pointer_cb(sensor_id, sensor_id_set_thresholds_cb, &info); if (!rv) rv = info.rv; return rv; } typedef struct sensor_id_thresholds_get_s { ipmi_sensor_thresholds_cb done; void *cb_data; int rv; } sensor_id_thresholds_get_t; static void sensor_id_get_thresholds_cb(ipmi_sensor_t *sensor, void *cb_data) { sensor_id_thresholds_get_t *info = cb_data; info->rv = ipmi_sensor_get_thresholds(sensor, info->done, info->cb_data); } int ipmi_sensor_id_get_thresholds(ipmi_sensor_id_t sensor_id, ipmi_sensor_thresholds_cb done, void *cb_data) { sensor_id_thresholds_get_t info; int rv; info.done = done; info.cb_data = cb_data; rv = ipmi_sensor_pointer_cb(sensor_id, sensor_id_get_thresholds_cb, &info); if (!rv) rv = info.rv; return rv; } typedef struct sensor_id_reading_get_s { ipmi_sensor_reading_cb done; void *cb_data; int rv; } sensor_id_reading_get_t; static void sensor_id_get_reading_cb(ipmi_sensor_t *sensor, void *cb_data) { sensor_id_reading_get_t *info = cb_data; info->rv = ipmi_sensor_get_reading(sensor, info->done, info->cb_data); } int ipmi_sensor_id_get_reading(ipmi_sensor_id_t sensor_id, ipmi_sensor_reading_cb done, void *cb_data) { sensor_id_reading_get_t info; int rv; info.done = done; info.cb_data = cb_data; rv = ipmi_sensor_pointer_cb(sensor_id, sensor_id_get_reading_cb, &info); if (!rv) rv = info.rv; return rv; } typedef struct sensor_id_states_get_s { ipmi_sensor_states_cb done; void *cb_data; int rv; } sensor_id_states_get_t; static void sensor_id_get_states_cb(ipmi_sensor_t *sensor, void *cb_data) { sensor_id_states_get_t *info = cb_data; info->rv = ipmi_sensor_get_states(sensor, info->done, info->cb_data); } int ipmi_sensor_id_get_states(ipmi_sensor_id_t sensor_id, ipmi_sensor_states_cb done, void *cb_data) { sensor_id_states_get_t info; int rv; info.done = done; info.cb_data = cb_data; rv = ipmi_sensor_pointer_cb(sensor_id, sensor_id_get_states_cb, &info); if (!rv) rv = info.rv; return rv; } #ifdef IPMI_CHECK_LOCKS void i__ipmi_check_sensor_lock(const ipmi_sensor_t *sensor) { if (!sensor) return; if (!DEBUG_LOCKS) return; CHECK_ENTITY_LOCK(sensor->entity); CHECK_MC_LOCK(sensor->mc); if (sensor->usecount == 0) ipmi_report_lock_error(ipmi_domain_get_os_hnd(sensor->domain), "sensor not locked when it should have been"); } #endif /*********************************************************************** * * Cruft * **********************************************************************/ int ipmi_sensor_threshold_assertion_event_supported( ipmi_sensor_t *sensor, enum ipmi_thresh_e event, enum ipmi_event_value_dir_e dir, int *val) { int idx; CHECK_SENSOR_LOCK(sensor); if (sensor->event_reading_type != IPMI_EVENT_READING_TYPE_THRESHOLD) /* Not a threshold sensor, it doesn't have readings. */ return ENOSYS; idx = (event * 2) + dir; if (idx > 11) return EINVAL; *val = IPMI_SENSOR_GET_MASK_BIT(sensor->mask1, idx); return 0; } int ipmi_sensor_threshold_deassertion_event_supported( ipmi_sensor_t *sensor, enum ipmi_thresh_e event, enum ipmi_event_value_dir_e dir, int *val) { int idx; CHECK_SENSOR_LOCK(sensor); if (sensor->event_reading_type != IPMI_EVENT_READING_TYPE_THRESHOLD) /* Not a threshold sensor, it doesn't have readings. */ return ENOSYS; idx = (event * 2) + dir; if (idx > 11) return 0; *val = IPMI_SENSOR_GET_MASK_BIT(sensor->mask2, idx); return 0; } int ipmi_sensor_discrete_assertion_event_supported(ipmi_sensor_t *sensor, int event, int *val) { CHECK_SENSOR_LOCK(sensor); if (sensor->event_reading_type == IPMI_EVENT_READING_TYPE_THRESHOLD) /* A threshold sensor, it doesn't have events. */ return ENOSYS; if (event > 14) return EINVAL; *val = IPMI_SENSOR_GET_MASK_BIT(sensor->mask1, event); return 0; } int ipmi_sensor_discrete_deassertion_event_supported(ipmi_sensor_t *sensor, int event, int *val) { CHECK_SENSOR_LOCK(sensor); if (sensor->event_reading_type == IPMI_EVENT_READING_TYPE_THRESHOLD) /* A threshold sensor, it doesn't have events. */ return ENOSYS; if (event > 14) return EINVAL; *val = IPMI_SENSOR_GET_MASK_BIT(sensor->mask2, event); return 0; } int ipmi_sensor_events_enable_get(ipmi_sensor_t *sensor, ipmi_sensor_event_enables_cb done, void *cb_data) { return ipmi_sensor_get_event_enables(sensor, done, cb_data); } int ipmi_sensor_events_disable(ipmi_sensor_t *sensor, ipmi_event_state_t *states, ipmi_sensor_done_cb done, void *cb_data) { return ipmi_sensor_disable_events(sensor, states, done, cb_data); } int ipmi_sensor_events_enable(ipmi_sensor_t *sensor, ipmi_event_state_t *states, ipmi_sensor_done_cb done, void *cb_data) { return ipmi_sensor_enable_events(sensor, states, done, cb_data); } int ipmi_sensor_events_enable_set(ipmi_sensor_t *sensor, ipmi_event_state_t *states, ipmi_sensor_done_cb done, void *cb_data) { return ipmi_sensor_set_event_enables(sensor, states, done, cb_data); } int ipmi_sensor_id_events_enable_set(ipmi_sensor_id_t sensor_id, ipmi_event_state_t *states, ipmi_sensor_done_cb done, void *cb_data) { return ipmi_sensor_id_set_event_enables(sensor_id, states, done, cb_data); } int ipmi_sensor_id_events_enable(ipmi_sensor_id_t sensor_id, ipmi_event_state_t *states, ipmi_sensor_done_cb done, void *cb_data) { return ipmi_sensor_id_enable_events(sensor_id, states, done, cb_data); } int ipmi_sensor_id_events_disable(ipmi_sensor_id_t sensor_id, ipmi_event_state_t *states, ipmi_sensor_done_cb done, void *cb_data) { return ipmi_sensor_id_disable_events(sensor_id, states, done, cb_data); } int ipmi_sensor_id_events_enable_get(ipmi_sensor_id_t sensor_id, ipmi_sensor_event_enables_cb done, void *cb_data) { return ipmi_sensor_id_get_event_enables(sensor_id, done, cb_data); } int ipmi_states_get(ipmi_sensor_t *sensor, ipmi_sensor_states_cb done, void *cb_data) { return ipmi_sensor_get_states(sensor, done, cb_data); } int ipmi_reading_get(ipmi_sensor_t *sensor, ipmi_sensor_reading_cb done, void *cb_data) { return ipmi_sensor_get_reading(sensor, done, cb_data); } int ipmi_thresholds_set(ipmi_sensor_t *sensor, ipmi_thresholds_t *thresholds, ipmi_sensor_done_cb done, void *cb_data) { return ipmi_sensor_set_thresholds(sensor, thresholds, done, cb_data); } int ipmi_thresholds_get(ipmi_sensor_t *sensor, ipmi_sensor_thresholds_cb done, void *cb_data) { return ipmi_sensor_get_thresholds(sensor, done, cb_data); } int ipmi_sensor_id_thresholds_set(ipmi_sensor_id_t sensor_id, ipmi_thresholds_t *thresholds, ipmi_sensor_done_cb done, void *cb_data) { return ipmi_sensor_id_set_thresholds(sensor_id, thresholds, done, cb_data); } int ipmi_sensor_id_thresholds_get(ipmi_sensor_id_t sensor_id, ipmi_sensor_thresholds_cb done, void *cb_data) { return ipmi_sensor_id_get_thresholds(sensor_id, done, cb_data); } int ipmi_sensor_id_reading_get(ipmi_sensor_id_t sensor_id, ipmi_sensor_reading_cb done, void *cb_data) { return ipmi_sensor_id_get_reading(sensor_id, done, cb_data); } int ipmi_sensor_id_states_get(ipmi_sensor_id_t sensor_id, ipmi_sensor_states_cb done, void *cb_data) { return ipmi_sensor_id_get_states(sensor_id, done, cb_data); } int ipmi_discrete_event_readable(ipmi_sensor_t *sensor, int event, int *val) { CHECK_SENSOR_LOCK(sensor); if (sensor->event_reading_type == IPMI_EVENT_READING_TYPE_THRESHOLD) /* A threshold sensor, it doesn't have events. */ return ENOSYS; if (event > 14) return EINVAL; *val = IPMI_SENSOR_GET_MASK_BIT(sensor->mask3, event); return 0; }