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; }
static config_err_t threshold_checkout (const char *section_name, struct config_keyvalue *kv, void *arg) { ipmi_sensors_config_state_data_t *state_data; fiid_obj_t obj_cmd_rs = NULL; config_err_t rv = CONFIG_ERR_FATAL_ERROR; config_err_t ret; char *readable_str; char *threshold_str; uint8_t readable; uint8_t threshold_raw; uint64_t val; double threshold_calc; uint8_t sensor_number; assert (section_name); assert (kv); assert (arg); state_data = (ipmi_sensors_config_state_data_t *)arg; if ((ret = seek_to_sdr_record (state_data, section_name)) != CONFIG_ERR_SUCCESS) { rv = ret; goto cleanup; } if (ipmi_sdr_parse_sensor_number (state_data->sdr_ctx, NULL, 0, &sensor_number) < 0) { pstdout_fprintf (state_data->pstate, stderr, "ipmi_sdr_parse_sensor_number: %s\n", ipmi_sdr_ctx_errormsg (state_data->sdr_ctx)); goto cleanup; } if (!(obj_cmd_rs = fiid_obj_create (tmpl_cmd_get_sensor_thresholds_rs))) { pstdout_fprintf (state_data->pstate, stderr, "fiid_obj_create: %s\n", strerror (errno)); goto cleanup; } if (ipmi_cmd_get_sensor_thresholds (state_data->ipmi_ctx, sensor_number, obj_cmd_rs) < 0) { if (state_data->prog_data->args->config_args.common_args.debug) pstdout_fprintf (state_data->pstate, stderr, "ipmi_cmd_get_sensor_thresholds: %s\n", ipmi_ctx_errormsg (state_data->ipmi_ctx)); if (config_is_non_fatal_error (state_data->ipmi_ctx, obj_cmd_rs, &ret)) rv = ret; /* * IPMI Workaround (achu) * * Discovered on HP DL585 * * Seems that the HP machine doesn't support the "Get Sensor * Thresholds" command. 99% of the time if a command is invalid * on a remote machine, that's a fatal error and we should exit. * I suppose this is an exception though. We can continue on * even if this command isn't supported. The user just doesn't * get to configure these thresholds. */ if (ipmi_ctx_errnum (state_data->ipmi_ctx) == IPMI_ERR_BAD_COMPLETION_CODE && ipmi_check_completion_code (obj_cmd_rs, IPMI_COMP_CODE_INVALID_COMMAND) == 1) rv = CONFIG_ERR_NON_FATAL_ERROR; goto cleanup; } if (!strcasecmp (kv->key->key_name, "Lower_Non_Critical_Threshold")) { readable_str = "readable_thresholds.lower_non_critical_threshold"; threshold_str = "lower_non_critical_threshold"; } else if (!strcasecmp (kv->key->key_name, "Lower_Critical_Threshold")) { readable_str = "readable_thresholds.lower_critical_threshold"; threshold_str = "lower_critical_threshold"; } else if (!strcasecmp (kv->key->key_name, "Lower_Non_Recoverable_Threshold")) { readable_str = "readable_thresholds.lower_non_recoverable_threshold"; threshold_str = "lower_non_recoverable_threshold"; } else if (!strcasecmp (kv->key->key_name, "Upper_Non_Critical_Threshold")) { readable_str = "readable_thresholds.upper_non_critical_threshold"; threshold_str = "upper_non_critical_threshold"; } else if (!strcasecmp (kv->key->key_name, "Upper_Critical_Threshold")) { readable_str = "readable_thresholds.upper_critical_threshold"; threshold_str = "upper_critical_threshold"; } else if (!strcasecmp (kv->key->key_name, "Upper_Non_Recoverable_Threshold")) { readable_str = "readable_thresholds.upper_non_recoverable_threshold"; threshold_str = "upper_non_recoverable_threshold"; } else /* unknown key_name - fatal error */ goto cleanup; if (FIID_OBJ_GET (obj_cmd_rs, readable_str, &val) < 0) { pstdout_fprintf (state_data->pstate, stderr, "fiid_obj_get: '%s': %s\n", readable_str, fiid_obj_errormsg (obj_cmd_rs)); goto cleanup; } readable = val; if (!readable) { /* Inconsistency w/ the SDR, should be readable */ if (state_data->prog_data->args->config_args.common_args.debug) pstdout_fprintf (state_data->pstate, stderr, "%s:%s - threshold not readable\n", section_name, kv->key->key_name); rv = CONFIG_ERR_NON_FATAL_ERROR; goto cleanup; } if (FIID_OBJ_GET (obj_cmd_rs, threshold_str, &val) < 0) { pstdout_fprintf (state_data->pstate, stderr, "fiid_obj_get: '%s': %s\n", threshold_str, fiid_obj_errormsg (obj_cmd_rs)); goto cleanup; } threshold_raw = val; if ((ret = _decode_value (state_data, threshold_raw, &threshold_calc)) != CONFIG_ERR_SUCCESS) { rv = ret; goto cleanup; } if (config_section_update_keyvalue_output_double (state_data->pstate, kv, threshold_calc) < 0) goto cleanup; rv = CONFIG_ERR_SUCCESS; cleanup: fiid_obj_destroy (obj_cmd_rs); return (rv); }