int ipmi_sensor_decode_tolerance (int8_t r_exponent, int16_t m, uint8_t linearization, uint8_t raw_data, double *value) { double dval = 0.0; if (!value || !IPMI_SDR_LINEARIZATION_IS_LINEAR (linearization)) { SET_ERRNO (EINVAL); return (-1); } /* note no analog_data format, tolerance always stored as unsigned */ dval = (double) raw_data; dval *= (double) m; dval /= 2.0; dval += (dval * pow (10, r_exponent)); switch (linearization) { case IPMI_SDR_LINEARIZATION_LN: dval = log (dval); break; case IPMI_SDR_LINEARIZATION_LOG10: dval = log10 (dval); break; case IPMI_SDR_LINEARIZATION_LOG2: dval = log2 (dval); break; case IPMI_SDR_LINEARIZATION_E: dval = exp (dval); break; case IPMI_SDR_LINEARIZATION_EXP10: dval = exp10 (dval); break; case IPMI_SDR_LINEARIZATION_EXP2: dval = exp2 (dval); break; case IPMI_SDR_LINEARIZATION_INVERSE: if (dval != 0.0) dval = 1.0 / dval; break; case IPMI_SDR_LINEARIZATION_SQR: dval = pow (dval, 2.0); break; case IPMI_SDR_LINEARIZATION_CUBE: dval = pow (dval, 3.0); break; case IPMI_SDR_LINEARIZATION_SQRT: dval = sqrt (dval); break; case IPMI_SDR_LINEARIZATION_CUBERT: dval = cbrt (dval); break; } *value = dval; return (0); }
int ipmi_sensor_decode_raw_value (int8_t r_exponent, int8_t b_exponent, int16_t m, int16_t b, uint8_t linearization, uint8_t analog_data_format, double value, uint8_t *raw_data) { double dval; uint8_t rval; if (!raw_data || !IPMI_SDR_ANALOG_DATA_FORMAT_VALID (analog_data_format) || !IPMI_SDR_LINEARIZATION_IS_LINEAR (linearization)) { SET_ERRNO (EINVAL); return (-1); } dval = value; /* achu: * * b/c I always forget: * * y = log_b(x) == x = b^y * * log_b(x) = log_k(x)/log(k(b) */ /* achu: the macros M_E or M_El for 'e' is questionably portable. * Folks online suggest just using exp(1.0) in its place. Sounds * good to me. */ switch (linearization) { case IPMI_SDR_LINEARIZATION_LN: dval = exp (dval); break; case IPMI_SDR_LINEARIZATION_LOG10: dval = exp10 (dval); break; case IPMI_SDR_LINEARIZATION_LOG2: dval = exp2 (dval); break; case IPMI_SDR_LINEARIZATION_E: dval = (log (dval)/log (exp (1.0))); break; case IPMI_SDR_LINEARIZATION_EXP10: dval = (log (dval)/log (10)); break; case IPMI_SDR_LINEARIZATION_EXP2: dval = (log (dval)/log (2)); break; case IPMI_SDR_LINEARIZATION_INVERSE: if (dval != 0.0) dval = 1.0 / dval; break; case IPMI_SDR_LINEARIZATION_SQR: dval = sqrt (dval); break; case IPMI_SDR_LINEARIZATION_CUBE: dval = cbrt (dval); break; case IPMI_SDR_LINEARIZATION_SQRT: dval = pow (dval, 2.0); break; case IPMI_SDR_LINEARIZATION_CUBERT: dval = pow (dval, 3.0); break; } dval = (dval / pow (10, r_exponent)); dval = (dval - (b * pow (10, b_exponent))); if (m) dval = (dval / m); /* Floating point arithmetic cannot guarantee us a perfect * conversion of raw to value and back to raw. This can * fix things. */ if ((dval - (int)dval) >= 0.5) dval = ceil (dval); else dval = floor (dval); if (analog_data_format == IPMI_SDR_ANALOG_DATA_FORMAT_UNSIGNED) rval = (uint8_t) dval; else if (analog_data_format == IPMI_SDR_ANALOG_DATA_FORMAT_1S_COMPLEMENT) { rval = (char)dval; if (rval & 0x80) rval--; } else /* analog_data_format == IPMI_SDR_ANALOG_DATA_FORMAT_2S_COMPLEMENT */ rval = (char)dval; *raw_data = rval; return (0); }
int ipmi_sensor_decode_value (int8_t r_exponent, int8_t b_exponent, int16_t m, int16_t b, uint8_t linearization, uint8_t analog_data_format, uint8_t raw_data, double *value) { double dval = 0.0; if (!value || !IPMI_SDR_ANALOG_DATA_FORMAT_VALID (analog_data_format) || !IPMI_SDR_LINEARIZATION_IS_LINEAR (linearization)) { SET_ERRNO (EINVAL); return (-1); } if (analog_data_format == IPMI_SDR_ANALOG_DATA_FORMAT_UNSIGNED) dval = (double) raw_data; else if (analog_data_format == IPMI_SDR_ANALOG_DATA_FORMAT_1S_COMPLEMENT) { if (raw_data & 0x80) raw_data++; dval = (double)((char) raw_data); } else /* analog_data_format == IPMI_SDR_ANALOG_DATA_FORMAT_2S_COMPLEMENT */ dval = (double)((char) raw_data); dval *= (double) m; dval += (b * pow (10, b_exponent)); dval *= pow (10, r_exponent); switch (linearization) { case IPMI_SDR_LINEARIZATION_LN: dval = log (dval); break; case IPMI_SDR_LINEARIZATION_LOG10: dval = log10 (dval); break; case IPMI_SDR_LINEARIZATION_LOG2: dval = log2 (dval); break; case IPMI_SDR_LINEARIZATION_E: dval = exp (dval); break; case IPMI_SDR_LINEARIZATION_EXP10: dval = exp10 (dval); break; case IPMI_SDR_LINEARIZATION_EXP2: dval = exp2 (dval); break; case IPMI_SDR_LINEARIZATION_INVERSE: if (dval != 0.0) dval = 1.0 / dval; break; case IPMI_SDR_LINEARIZATION_SQR: dval = pow (dval, 2.0); break; case IPMI_SDR_LINEARIZATION_CUBE: dval = pow (dval, 3.0); break; case IPMI_SDR_LINEARIZATION_SQRT: dval = sqrt (dval); break; case IPMI_SDR_LINEARIZATION_CUBERT: dval = cbrt (dval); break; } *value = dval; return (0); }
int ipmi_sensors_get_thresholds (ipmi_sensors_state_data_t *state_data, uint8_t *sdr_record, unsigned int sdr_record_len, double **lower_non_critical_threshold, double **lower_critical_threshold, double **lower_non_recoverable_threshold, double **upper_non_critical_threshold, double **upper_critical_threshold, double **upper_non_recoverable_threshold) { int8_t r_exponent, b_exponent; int16_t m, b; uint8_t linearization, analog_data_format; uint8_t sensor_number; fiid_obj_t obj_cmd_rs = NULL; double *tmp_lower_non_critical_threshold = NULL; double *tmp_lower_critical_threshold = NULL; double *tmp_lower_non_recoverable_threshold = NULL; double *tmp_upper_non_critical_threshold = NULL; double *tmp_upper_critical_threshold = NULL; double *tmp_upper_non_recoverable_threshold = NULL; double threshold; uint8_t threshold_access_support; uint64_t val; int rv = -1; assert(state_data); assert(sdr_record); assert(sdr_record_len); if (lower_non_critical_threshold) *lower_non_critical_threshold = NULL; if (lower_critical_threshold) *lower_critical_threshold = NULL; if (lower_non_recoverable_threshold) *lower_non_recoverable_threshold = NULL; if (upper_non_critical_threshold) *upper_non_critical_threshold = NULL; if (upper_critical_threshold) *upper_critical_threshold = NULL; if (upper_non_recoverable_threshold) *upper_non_recoverable_threshold = NULL; /* achu: first lets check if we have anything to output */ if (sdr_cache_get_sensor_capabilities (state_data->pstate, sdr_record, sdr_record_len, NULL, &threshold_access_support, NULL, NULL, NULL) < 0) goto cleanup; if (threshold_access_support == IPMI_SDR_NO_THRESHOLDS_SUPPORT || threshold_access_support == IPMI_SDR_FIXED_UNREADABLE_THRESHOLDS_SUPPORT) { rv = 0; goto cleanup; } /* achu: * * I will admit I'm not entirely sure what the best way is * to get thresholds. It seems the information is * stored/retrievable in the SDR and through an IPMI command. * * Since the readable_threshold_mask in the SDR record indicates the * mask is for the "Get Sensor Thresholds" command, it suggests the * best/right way is to get the values via that command. Sounds * good to me. Also, I suppose its possible that changes to the * thresholds may not be written to the SDR. * * Also, because the results from the get_sensor_thresholds include * readability flags, we can ignore the readability flags in the * SDR. * */ if (sdr_cache_get_sensor_number (state_data->pstate, sdr_record, sdr_record_len, &sensor_number) < 0) goto cleanup; if (sdr_cache_get_sensor_decoding_data(state_data->pstate, sdr_record, sdr_record_len, &r_exponent, &b_exponent, &m, &b, &linearization, &analog_data_format) < 0) goto cleanup; /* if the sensor is not analog, this is most likely a bug in the * SDR, since we shouldn't be decoding a non-threshold sensor. * * Don't return an error. Allow code to output "NA" or something. */ if (!IPMI_SDR_ANALOG_DATA_FORMAT_VALID(analog_data_format)) { if (state_data->prog_data->args->common.debug) pstdout_fprintf(state_data->pstate, stderr, "Attempting to decode non-analog sensor\n"); rv = 0; goto cleanup; } /* if the sensor is non-linear, I just don't know what to do * * Don't return an error. Allow code to output "NA" or something. */ if (!IPMI_SDR_LINEARIZATION_IS_LINEAR(linearization)) { if (state_data->prog_data->args->common.debug) pstdout_fprintf(state_data->pstate, stderr, "Cannot decode non-linear sensor\n"); rv = 0; goto cleanup; } _FIID_OBJ_CREATE(obj_cmd_rs, tmpl_cmd_get_sensor_thresholds_rs); if (ipmi_cmd_get_sensor_thresholds (state_data->ipmi_ctx, sensor_number, obj_cmd_rs) < 0) { if (state_data->prog_data->args->common.debug) pstdout_fprintf(state_data->pstate, stderr, "ipmi_cmd_get_sensor_thresholds: %s\n", ipmi_ctx_strerror(ipmi_ctx_errnum(state_data->ipmi_ctx))); if ((ipmi_ctx_errnum(state_data->ipmi_ctx) == IPMI_ERR_BAD_COMPLETION_CODE_REQUEST_DATA_INVALID) && (ipmi_check_completion_code(obj_cmd_rs, IPMI_COMP_CODE_COMMAND_ILLEGAL_FOR_SENSOR_OR_RECORD_TYPE) == 1 || ipmi_check_completion_code(obj_cmd_rs, IPMI_COMP_CODE_REQUEST_SENSOR_DATA_OR_RECORD_NOT_PRESENT) == 1)) { /* The thresholds cannot be gathered for one reason or * another, maybe b/c its a OEM sensor or something. We can * return 0 gracefully. */ rv = 0; goto cleanup; } /* * IPMI Workaround (achu) * * Discovered on HP DL585 * * Seems that the HP machine doesn't support the "Get Sensor * Thresholds" command. When this occurs, we assume the * information in the SDR is legit and up to date. Go get it * and fill in the object respectively. */ if ((ipmi_ctx_errnum(state_data->ipmi_ctx) == IPMI_ERR_BAD_COMPLETION_CODE_INVALID_COMMAND) && (ipmi_check_completion_code(obj_cmd_rs, IPMI_COMP_CODE_COMMAND_INVALID) == 1)) { if (state_data->prog_data->args->common.debug) pstdout_fprintf(state_data->pstate, stderr, "Get Sensor Thresholds failed, using SDR information\n"); if (_get_sdr_sensor_thresholds (state_data, sdr_record, sdr_record_len, obj_cmd_rs) < 0) goto cleanup; goto continue_get_sensor_thresholds; } goto cleanup; } continue_get_sensor_thresholds: if (lower_non_critical_threshold) { _FIID_OBJ_GET (obj_cmd_rs, "readable_thresholds.lower_non_critical_threshold", &val); if (val) { _FIID_OBJ_GET(obj_cmd_rs, "lower_non_critical_threshold", &val); if (ipmi_sensor_decode_value (r_exponent, b_exponent, m, b, linearization, analog_data_format, val, &threshold) < 0) { pstdout_fprintf (state_data->pstate, stderr, "ipmi_sensor_decode_value: %s\n", strerror(errno)); goto cleanup; } if (!(tmp_lower_non_critical_threshold = (double *)malloc(sizeof(double)))) { pstdout_perror(state_data->pstate, "malloc"); goto cleanup; } *tmp_lower_non_critical_threshold = threshold; } } if (lower_critical_threshold) { _FIID_OBJ_GET (obj_cmd_rs, "readable_thresholds.lower_critical_threshold", &val); if (val) { _FIID_OBJ_GET(obj_cmd_rs, "lower_critical_threshold", &val); if (ipmi_sensor_decode_value (r_exponent, b_exponent, m, b, linearization, analog_data_format, val, &threshold) < 0) { pstdout_fprintf (state_data->pstate, stderr, "ipmi_sensor_decode_value: %s\n", strerror(errno)); goto cleanup; } if (!(tmp_lower_critical_threshold = (double *)malloc(sizeof(double)))) { pstdout_perror(state_data->pstate, "malloc"); goto cleanup; } *tmp_lower_critical_threshold = threshold; } } if (lower_non_recoverable_threshold) { _FIID_OBJ_GET (obj_cmd_rs, "readable_thresholds.lower_non_recoverable_threshold", &val); if (val) { _FIID_OBJ_GET(obj_cmd_rs, "lower_non_recoverable_threshold", &val); if (ipmi_sensor_decode_value (r_exponent, b_exponent, m, b, linearization, analog_data_format, val, &threshold) < 0) { pstdout_fprintf (state_data->pstate, stderr, "ipmi_sensor_decode_value: %s\n", strerror(errno)); goto cleanup; } if (!(tmp_lower_non_recoverable_threshold = (double *)malloc(sizeof(double)))) { pstdout_perror(state_data->pstate, "malloc"); goto cleanup; } *tmp_lower_non_recoverable_threshold = threshold; } } if (upper_non_critical_threshold) { _FIID_OBJ_GET (obj_cmd_rs, "readable_thresholds.upper_non_critical_threshold", &val); if (val) { _FIID_OBJ_GET(obj_cmd_rs, "upper_non_critical_threshold", &val); if (ipmi_sensor_decode_value (r_exponent, b_exponent, m, b, linearization, analog_data_format, val, &threshold) < 0) { pstdout_fprintf (state_data->pstate, stderr, "ipmi_sensor_decode_value: %s\n", strerror(errno)); goto cleanup; } if (!(tmp_upper_non_critical_threshold = (double *)malloc(sizeof(double)))) { pstdout_perror(state_data->pstate, "malloc"); goto cleanup; } *tmp_upper_non_critical_threshold = threshold; } } if (upper_critical_threshold) { _FIID_OBJ_GET (obj_cmd_rs, "readable_thresholds.upper_critical_threshold", &val); if (val) { _FIID_OBJ_GET(obj_cmd_rs, "upper_critical_threshold", &val); if (ipmi_sensor_decode_value (r_exponent, b_exponent, m, b, linearization, analog_data_format, val, &threshold) < 0) { pstdout_fprintf (state_data->pstate, stderr, "ipmi_sensor_decode_value: %s\n", strerror(errno)); goto cleanup; } if (!(tmp_upper_critical_threshold = (double *)malloc(sizeof(double)))) { pstdout_perror(state_data->pstate, "malloc"); goto cleanup; } *tmp_upper_critical_threshold = threshold; } } if (upper_non_recoverable_threshold) { _FIID_OBJ_GET (obj_cmd_rs, "readable_thresholds.upper_non_recoverable_threshold", &val); if (val) { _FIID_OBJ_GET(obj_cmd_rs, "upper_non_recoverable_threshold", &val); if (ipmi_sensor_decode_value (r_exponent, b_exponent, m, b, linearization, analog_data_format, val, &threshold) < 0) { pstdout_fprintf (state_data->pstate, stderr, "ipmi_sensor_decode_value: %s\n", strerror(errno)); goto cleanup; } if (!(tmp_upper_non_recoverable_threshold = (double *)malloc(sizeof(double)))) { pstdout_perror(state_data->pstate, "malloc"); goto cleanup; } *tmp_upper_non_recoverable_threshold = threshold; } } if (lower_non_critical_threshold) *lower_non_critical_threshold = tmp_lower_non_critical_threshold; if (lower_critical_threshold) *lower_critical_threshold = tmp_lower_critical_threshold; if (lower_non_recoverable_threshold) *lower_non_recoverable_threshold = tmp_lower_non_recoverable_threshold; if (upper_non_critical_threshold) *upper_non_critical_threshold = tmp_upper_non_critical_threshold; if (upper_critical_threshold) *upper_critical_threshold = tmp_upper_critical_threshold; if (upper_non_recoverable_threshold) *upper_non_recoverable_threshold = tmp_upper_non_recoverable_threshold; rv = 0; cleanup: _FIID_OBJ_DESTROY(obj_cmd_rs); if (rv < 0) { if (tmp_lower_non_critical_threshold) free(tmp_lower_non_critical_threshold); if (tmp_lower_critical_threshold) free(tmp_lower_critical_threshold); if (tmp_lower_non_recoverable_threshold) free(tmp_lower_non_recoverable_threshold); if (tmp_upper_non_critical_threshold) free(tmp_upper_non_critical_threshold); if (tmp_upper_critical_threshold) free(tmp_upper_critical_threshold); if (tmp_upper_non_recoverable_threshold) free(tmp_upper_non_recoverable_threshold); } return rv; }
int ipmi_sensor_read (ipmi_sensor_read_ctx_t ctx, const void *sdr_record, unsigned int sdr_record_len, uint8_t shared_sensor_number_offset, uint8_t *sensor_reading_raw, double **sensor_reading, uint16_t *sensor_event_bitmask) { double *tmp_sensor_reading = NULL; uint64_t val; int rv = -1; fiid_obj_t obj_cmd_rs = NULL; uint8_t sensor_event_bitmask1 = 0; uint8_t sensor_event_bitmask2 = 0; int sensor_event_bitmask1_flag = 0; int sensor_event_bitmask2_flag = 0; uint16_t record_id = 0; uint8_t record_type = 0; uint8_t sensor_number = 0; uint8_t event_reading_type_code = 0; uint8_t sensor_owner_id_type = 0; uint8_t sensor_owner_id = 0; uint8_t sensor_owner_lun = 0; uint8_t channel_number = 0; uint8_t slave_address = 0; uint8_t reading_state, sensor_scanning; uint8_t local_sensor_reading_raw; unsigned int ctx_flags_orig; int event_reading_type_code_class = 0; if (!ctx || ctx->magic != IPMI_SENSOR_READ_CTX_MAGIC) { ERR_TRACE (ipmi_sensor_read_ctx_errormsg (ctx), ipmi_sensor_read_ctx_errnum (ctx)); return (-1); } if (!sdr_record || !sdr_record_len || !sensor_reading || !sensor_event_bitmask) { SENSOR_READ_SET_ERRNUM (ctx, IPMI_SENSOR_READ_ERR_PARAMETERS); return (-1); } *sensor_reading = NULL; *sensor_event_bitmask = 0; if (ipmi_sdr_parse_record_id_and_type (ctx->sdr_ctx, sdr_record, sdr_record_len, &record_id, &record_type) < 0) { SENSOR_READ_SET_ERRNUM (ctx, IPMI_SENSOR_READ_ERR_SDR_ENTRY_ERROR); goto cleanup; } if (record_type != IPMI_SDR_FORMAT_FULL_SENSOR_RECORD && record_type != IPMI_SDR_FORMAT_COMPACT_SENSOR_RECORD) { SENSOR_READ_SET_ERRNUM (ctx, IPMI_SENSOR_READ_ERR_INVALID_SDR_RECORD_TYPE); goto cleanup; } if (ipmi_sdr_parse_sensor_owner_id (ctx->sdr_ctx, sdr_record, sdr_record_len, &sensor_owner_id_type, &sensor_owner_id) < 0) { SENSOR_READ_SET_ERRNUM (ctx, IPMI_SENSOR_READ_ERR_SDR_ENTRY_ERROR); goto cleanup; } if (ipmi_sdr_parse_sensor_owner_lun (ctx->sdr_ctx, sdr_record, sdr_record_len, &sensor_owner_lun, &channel_number) < 0) { SENSOR_READ_SET_ERRNUM (ctx, IPMI_SENSOR_READ_ERR_SDR_ENTRY_ERROR); goto cleanup; } if (ipmi_sdr_parse_sensor_number (ctx->sdr_ctx, sdr_record, sdr_record_len, &sensor_number) < 0) { SENSOR_READ_SET_ERRNUM (ctx, IPMI_SENSOR_READ_ERR_SDR_ENTRY_ERROR); goto cleanup; } if (shared_sensor_number_offset) { uint8_t share_count; if (record_type != IPMI_SDR_FORMAT_COMPACT_SENSOR_RECORD) { SENSOR_READ_SET_ERRNUM (ctx, IPMI_SENSOR_READ_ERR_INVALID_SDR_RECORD_TYPE); goto cleanup; } if (ipmi_sdr_parse_sensor_record_sharing (ctx->sdr_ctx, sdr_record, sdr_record_len, &share_count, NULL, NULL, NULL) < 0) { SENSOR_READ_SET_ERRNUM (ctx, IPMI_SENSOR_READ_ERR_SDR_ENTRY_ERROR); goto cleanup; } if (share_count <= 1) { SENSOR_READ_SET_ERRNUM (ctx, IPMI_SENSOR_READ_ERR_INVALID_SDR_RECORD_TYPE); goto cleanup; } if ((sensor_number + share_count) < (sensor_number + shared_sensor_number_offset)) { SENSOR_READ_SET_ERRNUM (ctx, IPMI_SENSOR_READ_ERR_PARAMETERS); goto cleanup; } sensor_number += shared_sensor_number_offset; } if (ipmi_sdr_parse_event_reading_type_code (ctx->sdr_ctx, sdr_record, sdr_record_len, &event_reading_type_code) < 0) { SENSOR_READ_SET_ERRNUM (ctx, IPMI_SENSOR_READ_ERR_SDR_ENTRY_ERROR); goto cleanup; } if (sensor_owner_id_type == IPMI_SDR_SENSOR_OWNER_ID_TYPE_SYSTEM_SOFTWARE_ID) { SENSOR_READ_SET_ERRNUM (ctx, IPMI_SENSOR_READ_ERR_SENSOR_IS_SYSTEM_SOFTWARE); goto cleanup; } slave_address = (sensor_owner_id << 1) | sensor_owner_id_type; if (!(obj_cmd_rs = fiid_obj_create (tmpl_cmd_get_sensor_reading_rs))) { SENSOR_READ_ERRNO_TO_SENSOR_READ_ERRNUM (ctx, errno); goto cleanup; } /* * IPMI Workaround (achu) * * See comments below concerning sensor_event_bitmask. */ if (ipmi_ctx_get_flags (ctx->ipmi_ctx, &ctx_flags_orig) < 0) { SENSOR_READ_SET_ERRNUM (ctx, IPMI_SENSOR_READ_ERR_INTERNAL_ERROR); goto cleanup; } if (ipmi_ctx_set_flags (ctx->ipmi_ctx, ctx_flags_orig | IPMI_FLAGS_NO_VALID_CHECK) < 0) { SENSOR_READ_SET_ERRNUM (ctx, IPMI_SENSOR_READ_ERR_INTERNAL_ERROR); goto cleanup; } /* IPMI Workaround * * Discovered on Fujitsu RX300 * Discovered on Fujitsu RX300S2 * * On some motherboards, the sensor owner is invalid. The sensor * owner as atually the BMC. */ if (!(ctx->flags & IPMI_SENSOR_READ_FLAGS_ASSUME_BMC_OWNER)) { if (slave_address == IPMI_SLAVE_ADDRESS_BMC) { if (_get_sensor_reading (ctx, sensor_number, obj_cmd_rs) < 0) goto cleanup; } else { if (_get_sensor_reading_ipmb (ctx, slave_address, sensor_owner_lun, channel_number, sensor_number, obj_cmd_rs) < 0) goto cleanup; } } else { if (_get_sensor_reading (ctx, sensor_number, obj_cmd_rs) < 0) goto cleanup; } /* * IPMI Workaround (achu) * * See comments below concerning sensor_event_bitmask. */ if (ipmi_ctx_set_flags (ctx->ipmi_ctx, ctx_flags_orig) < 0) { SENSOR_READ_SET_ERRNUM (ctx, IPMI_SENSOR_READ_ERR_INTERNAL_ERROR); goto cleanup; } if (FIID_OBJ_GET (obj_cmd_rs, "reading_state", &val) < 0) { SENSOR_READ_FIID_OBJECT_ERROR_TO_SENSOR_READ_ERRNUM (ctx, obj_cmd_rs); goto cleanup; } reading_state = val; if (reading_state == IPMI_SENSOR_READING_STATE_UNAVAILABLE) { SENSOR_READ_SET_ERRNUM (ctx, IPMI_SENSOR_READ_ERR_SENSOR_READING_UNAVAILABLE); goto cleanup; } /* IPMI Workaround * * Discovered on Dell Poweredge 2900 * Discovered on Dell Poweredge 2950 * Discovered on Dell Poweredge R410 * Discovered on Dell Poweredge R610 * * On some motherboards, the sensor scanning bit is invalid for sensors. */ if (!(ctx->flags & IPMI_SENSOR_READ_FLAGS_IGNORE_SCANNING_DISABLED)) { if (FIID_OBJ_GET (obj_cmd_rs, "sensor_scanning", &val) < 0) { SENSOR_READ_FIID_OBJECT_ERROR_TO_SENSOR_READ_ERRNUM (ctx, obj_cmd_rs); goto cleanup; } sensor_scanning = val; if (sensor_scanning == IPMI_SENSOR_SCANNING_ON_THIS_SENSOR_DISABLE) { SENSOR_READ_SET_ERRNUM (ctx, IPMI_SENSOR_READ_ERR_SENSOR_SCANNING_DISABLED); goto cleanup; } } /* achu: * * Note: I don't bother checking the "all_event_messages" flag from * the get_sensor_reading response. If that stuff is turned off, * the bitmasks should be zeroed out. * * Hopefully this doesn't bite me later on. * * Call the normal fiid_obj_get instead of the wrapper, if the field * isn't set, we want to know and not error out. */ if ((sensor_event_bitmask1_flag = fiid_obj_get (obj_cmd_rs, "sensor_event_bitmask1", &val)) < 0) { SENSOR_READ_FIID_OBJECT_ERROR_TO_SENSOR_READ_ERRNUM (ctx, obj_cmd_rs); goto cleanup; } sensor_event_bitmask1 = val; if ((sensor_event_bitmask2_flag = fiid_obj_get (obj_cmd_rs, "sensor_event_bitmask2", &val)) < 0) { SENSOR_READ_FIID_OBJECT_ERROR_TO_SENSOR_READ_ERRNUM (ctx, obj_cmd_rs); goto cleanup; } sensor_event_bitmask2 = val; /* * IPMI Workaround (achu) * * Discovered on Dell 2950. * * It seems the sensor_event_bitmask (16 bits) may not be returned * by the server at all for some sensors, despite a minimum of 8 * bits being required. Under this situation, there's not much that * can be done. Since there is no sensor_event_bitmask, we just * assume that no states have been asserted and the * sensor_event_bitmask = 0; */ if (!sensor_event_bitmask1_flag && !sensor_event_bitmask2_flag) (*sensor_event_bitmask) = 0; else if (sensor_event_bitmask1_flag && sensor_event_bitmask2_flag) (*sensor_event_bitmask) = sensor_event_bitmask1 | (sensor_event_bitmask2 << 8); else if (sensor_event_bitmask1_flag && !sensor_event_bitmask2_flag) (*sensor_event_bitmask) = sensor_event_bitmask1; else { SENSOR_READ_SET_ERRNUM (ctx, IPMI_SENSOR_READ_ERR_IPMI_ERROR); goto cleanup; } if (FIID_OBJ_GET (obj_cmd_rs, "sensor_reading", &val) < 0) { SENSOR_READ_FIID_OBJECT_ERROR_TO_SENSOR_READ_ERRNUM (ctx, obj_cmd_rs); goto cleanup; } local_sensor_reading_raw = val; if (sensor_reading_raw) (*sensor_reading_raw) = local_sensor_reading_raw; event_reading_type_code_class = ipmi_event_reading_type_code_class (event_reading_type_code); if (event_reading_type_code_class == IPMI_EVENT_READING_TYPE_CODE_CLASS_THRESHOLD) { if (record_type == IPMI_SDR_FORMAT_FULL_SENSOR_RECORD) { int8_t r_exponent, b_exponent; int16_t m, b; uint8_t linearization, analog_data_format; if (ipmi_sdr_parse_sensor_decoding_data (ctx->sdr_ctx, sdr_record, sdr_record_len, &r_exponent, &b_exponent, &m, &b, &linearization, &analog_data_format) < 0) { SENSOR_READ_SET_ERRNUM (ctx, IPMI_SENSOR_READ_ERR_SDR_ENTRY_ERROR); goto cleanup; } /* if the sensor is not analog, this is most likely a bug in the * SDR, since we shouldn't be decoding a non-threshold sensor. */ if (!IPMI_SDR_ANALOG_DATA_FORMAT_VALID (analog_data_format)) { SENSOR_READ_SET_ERRNUM (ctx, IPMI_SENSOR_READ_ERR_SENSOR_NON_ANALOG); rv = 0; goto cleanup; } /* if the sensor is non-linear, I just don't know what to do, * let the tool figure out what to output. */ if (!IPMI_SDR_LINEARIZATION_IS_LINEAR (linearization)) { SENSOR_READ_SET_ERRNUM (ctx, IPMI_SENSOR_READ_ERR_SENSOR_NON_LINEAR); rv = 0; goto cleanup; } if (!(tmp_sensor_reading = (double *)malloc (sizeof (double)))) { SENSOR_READ_SET_ERRNUM (ctx, IPMI_SENSOR_READ_ERR_OUT_OF_MEMORY); goto cleanup; } if (ipmi_sensor_decode_value (r_exponent, b_exponent, m, b, linearization, analog_data_format, local_sensor_reading_raw, tmp_sensor_reading) < 0) { SENSOR_READ_SET_ERRNUM (ctx, IPMI_SENSOR_READ_ERR_INTERNAL_ERROR); goto cleanup; } *sensor_reading = tmp_sensor_reading; } rv = 1; } else if (event_reading_type_code_class == IPMI_EVENT_READING_TYPE_CODE_CLASS_GENERIC_DISCRETE || event_reading_type_code_class == IPMI_EVENT_READING_TYPE_CODE_CLASS_SENSOR_SPECIFIC_DISCRETE) { /* * IPMI Workaround (achu) * * Discovered on HP Proliant DL380 G7 * Discovered on HP ProLiant ML310 G5 * * SDR records for some sensors give conflicting information. A * threshold based sensor lists an event/reading type code for a * discrete sensor. The analog data format indicates an * analog/threshold based sensor, however no threshold limits * for the sensor are listed in the SDR. * * To deal with this, if the analog data format and units * strongly suggest that a reading should occur with this * sensor, get the reading and return it. * * Note that this can only occur for full records, since * decoding data does not exist in compact records. */ if (ctx->flags & IPMI_SENSOR_READ_FLAGS_DISCRETE_READING && record_type == IPMI_SDR_FORMAT_FULL_SENSOR_RECORD) { int8_t r_exponent, b_exponent; int16_t m, b; uint8_t linearization, analog_data_format; uint8_t sensor_units_percentage; uint8_t sensor_units_modifier; uint8_t sensor_units_rate; uint8_t sensor_base_unit_type; uint8_t sensor_modifier_unit_type; if (ipmi_sdr_parse_sensor_decoding_data (ctx->sdr_ctx, sdr_record, sdr_record_len, &r_exponent, &b_exponent, &m, &b, &linearization, &analog_data_format) < 0) { SENSOR_READ_SET_ERRNUM (ctx, IPMI_SENSOR_READ_ERR_SDR_ENTRY_ERROR); goto cleanup; } if (ipmi_sdr_parse_sensor_units (ctx->sdr_ctx, sdr_record, sdr_record_len, &sensor_units_percentage, &sensor_units_modifier, &sensor_units_rate, &sensor_base_unit_type, &sensor_modifier_unit_type) < 0) { SENSOR_READ_SET_ERRNUM (ctx, IPMI_SENSOR_READ_ERR_SDR_ENTRY_ERROR); goto cleanup; } /* if the sensor is not analog, this is normal expected * case, fallthrough to normal expectations */ if (!IPMI_SDR_ANALOG_DATA_FORMAT_VALID (analog_data_format)) { rv = 1; goto cleanup; } /* if the sensor units are not specified, this is the normal expected * case, fallthrough to normal expectations */ if (sensor_units_percentage != IPMI_SDR_PERCENTAGE_YES && sensor_base_unit_type == IPMI_SENSOR_UNIT_UNSPECIFIED) { rv = 1; goto cleanup; } /* if the sensor is non-linear, I just don't know what to do, * let the tool figure out what to output. */ if (!IPMI_SDR_LINEARIZATION_IS_LINEAR (linearization)) { SENSOR_READ_SET_ERRNUM (ctx, IPMI_SENSOR_READ_ERR_SENSOR_NON_LINEAR); rv = 0; goto cleanup; } if (!(tmp_sensor_reading = (double *)malloc (sizeof (double)))) { SENSOR_READ_SET_ERRNUM (ctx, IPMI_SENSOR_READ_ERR_OUT_OF_MEMORY); goto cleanup; } if (ipmi_sensor_decode_value (r_exponent, b_exponent, m, b, linearization, analog_data_format, local_sensor_reading_raw, tmp_sensor_reading) < 0) { SENSOR_READ_SET_ERRNUM (ctx, IPMI_SENSOR_READ_ERR_INTERNAL_ERROR); goto cleanup; } *sensor_reading = tmp_sensor_reading; } rv = 1; } else if (event_reading_type_code_class == IPMI_EVENT_READING_TYPE_CODE_CLASS_OEM) /* nothing to do, sensor_event_bitmask already set */ rv = 1; else rv = 0; cleanup: fiid_obj_destroy (obj_cmd_rs); if (rv <= 0) free (tmp_sensor_reading); return (rv); }
static config_err_t _get_sdr_decoding_data (ipmi_sensors_config_state_data_t *state_data, int8_t *r_exponent, int8_t *b_exponent, int16_t *m, int16_t *b, uint8_t *linearization, uint8_t *analog_data_format) { config_err_t rv = CONFIG_ERR_FATAL_ERROR; assert (state_data); assert (r_exponent); assert (b_exponent); assert (m); assert (b); assert (linearization); assert (analog_data_format); if (ipmi_sdr_parse_sensor_decoding_data (state_data->sdr_ctx, NULL, 0, r_exponent, b_exponent, m, b, linearization, analog_data_format) < 0) { pstdout_fprintf (state_data->pstate, stderr, "ipmi_sdr_parse_sensor_decoding_data: %s\n", ipmi_sdr_ctx_errormsg (state_data->sdr_ctx)); goto cleanup; } /* if the sensor is not analog, this is most likely a bug in the * SDR, since we shouldn't be decoding a non-threshold sensor. */ if (!IPMI_SDR_ANALOG_DATA_FORMAT_VALID (*analog_data_format)) { if (state_data->prog_data->args->config_args.common_args.debug) pstdout_fprintf (state_data->pstate, stderr, "Attempting to decode non-analog threshold\n"); rv = CONFIG_ERR_NON_FATAL_ERROR; goto cleanup; } /* if the sensor is non-linear, I just don't know what to do */ if (!IPMI_SDR_LINEARIZATION_IS_LINEAR (*linearization)) { if (state_data->prog_data->args->config_args.common_args.debug) pstdout_fprintf (state_data->pstate, stderr, "Cannot decode non-linear threshold\n"); rv = CONFIG_ERR_NON_FATAL_ERROR; goto cleanup; } rv = CONFIG_ERR_SUCCESS; cleanup: return (rv); }