Beispiel #1
0
void
api_set_api_errnum_by_bad_response (ipmi_ctx_t ctx, fiid_obj_t obj_cmd_rs)
{
  assert (ctx && ctx->magic == IPMI_CTX_MAGIC);

  /* IPMI_COMP_CODE_COMMAND_TIMEOUT, assumes it's a IPMB or command
   * specific timeout, so set to "MESSAGE_TIMEOUT" so user can
   * continue on if they wish.  At minimum, returned by openipmi
   * driver for (what seems to be) collection of potential errors.
   */
  if (ipmi_check_completion_code (obj_cmd_rs, IPMI_COMP_CODE_COMMAND_TIMEOUT) == 1)
    ctx->errnum = IPMI_ERR_MESSAGE_TIMEOUT;
  else if (ipmi_check_completion_code (obj_cmd_rs, IPMI_COMP_CODE_NODE_BUSY) == 1
	   || ipmi_check_completion_code (obj_cmd_rs, IPMI_COMP_CODE_OUT_OF_SPACE) == 1
	   || ipmi_check_completion_code (obj_cmd_rs, IPMI_COMP_CODE_SDR_REPOSITORY_IN_UPDATE_MODE) == 1
	   || ipmi_check_completion_code (obj_cmd_rs, IPMI_COMP_CODE_DEVICE_IN_FIRMWARE_UPDATE_MODE) == 1
	   || ipmi_check_completion_code (obj_cmd_rs, IPMI_COMP_CODE_BMC_INITIALIZATION_IN_PROGRESS) == 1)
    ctx->errnum = IPMI_ERR_BMC_BUSY;
  else if (ipmi_check_completion_code (obj_cmd_rs, IPMI_COMP_CODE_INSUFFICIENT_PRIVILEGE_LEVEL) == 1)
    ctx->errnum = IPMI_ERR_PRIVILEGE_LEVEL_INSUFFICIENT;
  else if (ipmi_check_completion_code (obj_cmd_rs, IPMI_COMP_CODE_INVALID_COMMAND) == 1
	   || ipmi_check_completion_code (obj_cmd_rs, IPMI_COMP_CODE_COMMAND_INVALID_FOR_LUN) == 1
	   || ipmi_check_completion_code (obj_cmd_rs, IPMI_COMP_CODE_REQUEST_DATA_LENGTH_INVALID) == 1
	   || ipmi_check_completion_code (obj_cmd_rs, IPMI_COMP_CODE_REQUEST_DATA_LENGTH_LIMIT_EXCEEDED) == 1
	   || ipmi_check_completion_code (obj_cmd_rs, IPMI_COMP_CODE_PARAMETER_OUT_OF_RANGE) == 1
	   || ipmi_check_completion_code (obj_cmd_rs, IPMI_COMP_CODE_INVALID_DATA_FIELD_IN_REQUEST) == 1)
    ctx->errnum = IPMI_ERR_COMMAND_INVALID_OR_UNSUPPORTED;
  else
    ctx->errnum = IPMI_ERR_BAD_COMPLETION_CODE;
}
int
ipmi_oem_get_system_info_string (ipmi_oem_state_data_t *state_data,
				 uint8_t parameter_selector,
				 uint8_t set_selector,
				 uint8_t block_selector,
				 char *string,
				 unsigned int string_len,
				 unsigned int *string_len_ret)
{
  fiid_obj_t obj_cmd_rs = NULL;
  uint8_t configuration_parameter_data[IPMI_OEM_MAX_BYTES];
  int len;
  int rv = -1;

  assert (state_data);
  assert (string);
  assert (string_len);

  if (!(obj_cmd_rs = fiid_obj_create (tmpl_cmd_get_system_info_parameters_rs)))
    {
      pstdout_fprintf (state_data->pstate,
                       stderr,
                       "fiid_obj_create: %s\n",
                       strerror (errno));
      goto cleanup;
    }

  if (ipmi_cmd_get_system_info_parameters (state_data->ipmi_ctx,
                                           IPMI_GET_SYSTEM_INFO_PARAMETER,
                                           parameter_selector,
					   set_selector,
					   block_selector,
                                           obj_cmd_rs) < 0)
    {
      if ((ipmi_ctx_errnum (state_data->ipmi_ctx) == IPMI_ERR_BAD_COMPLETION_CODE
	   && ipmi_check_completion_code (obj_cmd_rs,
					  IPMI_COMP_CODE_GET_SYSTEM_INFO_PARAMETERS_PARAMETER_NOT_SUPPORTED) == 1)
	  || (ipmi_ctx_errnum (state_data->ipmi_ctx) == IPMI_ERR_COMMAND_INVALID_OR_UNSUPPORTED
	      && ipmi_check_completion_code (obj_cmd_rs,
					     IPMI_COMP_CODE_INVALID_DATA_FIELD_IN_REQUEST) == 1))
	{
	  pstdout_fprintf (state_data->pstate,
			   stderr,
			   "%s:%s '%s' option not supported on this system\n",
			   state_data->prog_data->args->oem_id,
			   state_data->prog_data->args->oem_command,
			   state_data->prog_data->args->oem_options[0]);
	  goto cleanup;
	}
      
      pstdout_fprintf (state_data->pstate,
                       stderr,
                       "ipmi_cmd_get_system_info_parameters: %s\n",
                       ipmi_ctx_errormsg (state_data->ipmi_ctx));
      goto cleanup;
    }

  if ((len = fiid_obj_get_data (obj_cmd_rs,
                                "configuration_parameter_data",
                                configuration_parameter_data,
                                IPMI_OEM_MAX_BYTES)) < 0)
    {
      pstdout_fprintf (state_data->pstate,
                       stderr,
                       "fiid_obj_get_data: 'configuration_parameter_data': %s\n",
                       fiid_obj_errormsg (obj_cmd_rs));
      goto cleanup;
    }

  if (len > string_len)
    {
      pstdout_fprintf (state_data->pstate,
		       stderr,
		       "buffer overflow\n");
      goto cleanup;
    }
  
  memcpy (string,
	  &(configuration_parameter_data[0]),
	  len);

  if (string_len_ret)
    (*string_len_ret) = len;

  rv = 0;
 cleanup:
  fiid_obj_destroy (obj_cmd_rs);
  return (rv);
}
Beispiel #3
0
int
ipmi_check_completion_code_success (fiid_obj_t obj_cmd)
{
  return (ipmi_check_completion_code (obj_cmd, IPMI_COMP_CODE_COMMAND_SUCCESS));
}
static config_err_t
_set_alert_policy_table (struct pef_config_state_data *state_data, 
                         const char *section_name,
                         struct alert_policy_table *apt)
{
  fiid_obj_t obj_cmd_rs = NULL;
  config_err_t rv = CONFIG_ERR_FATAL_ERROR;
  uint8_t alert_policy_entry_number;

  assert(state_data);
  assert(section_name);
  assert(apt);

  alert_policy_entry_number = atoi (section_name + strlen ("Alert_Policy_"));

  _FIID_OBJ_CREATE(obj_cmd_rs, tmpl_cmd_set_pef_configuration_parameters_rs);

  if (ipmi_cmd_set_pef_configuration_parameters_alert_policy_table (state_data->ipmi_ctx, 
								    alert_policy_entry_number, 
								    apt->policy_type, 
								    apt->policy_enabled, 
								    apt->policy_number, 
								    apt->destination_selector, 
								    apt->channel_number, 
								    apt->alert_string_set_selector, 
								    apt->event_specific_alert_string, 
								    obj_cmd_rs) < 0)
    {
      if (state_data->prog_data->args->config_args.common.debug)
        pstdout_fprintf(state_data->pstate,
                        stderr,
                        "ipmi_cmd_set_pef_configuration_parameters_alert_policy_table: %s\n",
                        ipmi_ctx_strerror(ipmi_ctx_errnum(state_data->ipmi_ctx)));
      
      /* IPMI Workaround
       *
       * Fujitsu RX 100 S5
       *
       * All fields have to be applied simultaneously, the motherboard
       * does not appear to like configuration of one field of a time,
       * always leading to invalid input errors.
       */
      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_REQUEST_INVALID_DATA_FIELD) == 1))
        {
          struct config_section *section = NULL;
          struct config_keyvalue *kv;
          unsigned int i;
          
          for (i = 0; i < state_data->alert_policy_sections_len; i++)
            {
              if (!strcasecmp (section_name, state_data->alert_policy_sections[i]->section_name))
                {
                  section = state_data->alert_policy_sections[i];
                  break;
                }
            }
          
          /* shouldn't be possible */
          if (!section)
            goto cleanup;
          
          if ((kv = config_find_keyvalue (state_data->pstate,
                                          section,
                                          "Policy_Type")))
            apt->policy_type = policy_type_number (kv->value_input);
          
          if ((kv = config_find_keyvalue (state_data->pstate,
                                          section,
                                          "Policy_Enabled")))
            apt->policy_enabled = same (kv->value_input, "yes");
          
          if ((kv = config_find_keyvalue (state_data->pstate,
                                          section,
                                          "Policy_Number")))
            apt->policy_number = atoi (kv->value_input);
          
          if ((kv = config_find_keyvalue (state_data->pstate,
                                          section,
                                          "Destination_Selector")))
            apt->destination_selector = atoi (kv->value_input);
          
          if ((kv = config_find_keyvalue (state_data->pstate,
                                          section,
                                          "Channel_Number")))
            apt->channel_number = atoi (kv->value_input);
          
          if ((kv = config_find_keyvalue (state_data->pstate,
                                          section,
                                          "Alert_String_Set_Selector")))
            apt->alert_string_set_selector = atoi (kv->value_input);
          
          if ((kv = config_find_keyvalue (state_data->pstate,
                                          section,
                                          "Event_Specific_Alert_String")))
            apt->event_specific_alert_string = same (kv->value_input, "yes");
          
          if (state_data->prog_data->args->config_args.common.debug)
            pstdout_fprintf (state_data->pstate,
                             stderr,
                             "ipmi_cmd_set_pef_configuration_parameters_alert_policy_table: attempting workaround\n");

          if (ipmi_cmd_set_pef_configuration_parameters_alert_policy_table (state_data->ipmi_ctx,
                                                                            alert_policy_entry_number,
                                                                            apt->policy_type,
                                                                            apt->policy_enabled,
                                                                            apt->policy_number,
                                                                            apt->destination_selector,
                                                                            apt->channel_number,
                                                                            apt->alert_string_set_selector,
                                                                            apt->event_specific_alert_string,
                                                                            obj_cmd_rs) < 0)
            {
              if (state_data->prog_data->args->config_args.common.debug)
                pstdout_fprintf (state_data->pstate,
                                 stderr,
                                 "ipmi_cmd_set_pef_configuration_parameters_alert_policy_table: %s\n",
                                 ipmi_ctx_strerror(ipmi_ctx_errnum(state_data->ipmi_ctx)));
              
              if (!IPMI_CTX_ERRNUM_IS_FATAL_ERROR(state_data->ipmi_ctx))
                rv = CONFIG_ERR_NON_FATAL_ERROR;

              goto cleanup;
            }

          /* success */
          goto out;
        }
      else if (!IPMI_CTX_ERRNUM_IS_FATAL_ERROR(state_data->ipmi_ctx))
        rv = CONFIG_ERR_NON_FATAL_ERROR;

      goto cleanup;
    }
      
 out:
  rv = CONFIG_ERR_SUCCESS;
 cleanup:
  _FIID_OBJ_DESTROY(obj_cmd_rs);
  return (rv);
}
static config_err_t
_set_authentication_type_enables (bmc_config_state_data_t *state_data,
				  const char *section_name,
                                  struct bmc_authentication_level *al)
{
  fiid_obj_t obj_cmd_rs = NULL;
  config_err_t rv = CONFIG_ERR_FATAL_ERROR;
  config_err_t ret;
  uint8_t channel_number;

  assert (state_data);
  assert (section_name);
  assert (al);

  if (!(obj_cmd_rs = fiid_obj_create (tmpl_cmd_set_lan_configuration_parameters_rs)))
    {
      pstdout_fprintf (state_data->pstate,
                       stderr,
                       "fiid_obj_create: %s\n",
                       strerror (errno));
      goto cleanup;
    }

  if ((ret = get_lan_channel_number (state_data, section_name, &channel_number)) != CONFIG_ERR_SUCCESS)
    {
      rv = ret;
      goto cleanup;
    }

  if (ipmi_cmd_set_lan_configuration_parameters_authentication_type_enables (state_data->ipmi_ctx,
                                                                             channel_number,
                                                                             al->callback_level_none,
                                                                             al->callback_level_md2,
                                                                             al->callback_level_md5,
                                                                             al->callback_level_straight_password,
                                                                             al->callback_level_oem_proprietary,
                                                                             al->user_level_none,
                                                                             al->user_level_md2,
                                                                             al->user_level_md5,
                                                                             al->user_level_straight_password,
                                                                             al->user_level_oem_proprietary,
                                                                             al->operator_level_none,
                                                                             al->operator_level_md2,
                                                                             al->operator_level_md5,
                                                                             al->operator_level_straight_password,
                                                                             al->operator_level_oem_proprietary,
                                                                             al->admin_level_none,
                                                                             al->admin_level_md2,
                                                                             al->admin_level_md5,
                                                                             al->admin_level_straight_password,
                                                                             al->admin_level_oem_proprietary,
                                                                             al->oem_level_none,
                                                                             al->oem_level_md2,
                                                                             al->oem_level_md5,
                                                                             al->oem_level_straight_password,
                                                                             al->oem_level_oem_proprietary,
                                                                             obj_cmd_rs) < 0)
    {
      if (state_data->prog_data->args->config_args.common_args.debug)
        pstdout_fprintf (state_data->pstate,
                         stderr,
                         "ipmi_cmd_set_lan_configuration_parameters_authentication_type_enables: %s\n",
                         ipmi_ctx_errormsg (state_data->ipmi_ctx));

      /*
       * IPMI Workaround
       *
       * Dell Poweredge R610
       *
       * Nodes come default w/ OEM authentication enables turned
       * on, but you cannot configure them on.  So this always
       * leads to invalid data errors (0xCC) b/c we are
       * configuring one field at a time.  So we will "absorb" the
       * OEM configuration of later fields and try again, hoping
       * that the user has tried to "right" the badness already
       * sitting on the motherboard.
       */
      if (ipmi_ctx_errnum (state_data->ipmi_ctx) == IPMI_ERR_COMMAND_INVALID_OR_UNSUPPORTED
          && (ipmi_check_completion_code (obj_cmd_rs,
                                          IPMI_COMP_CODE_INVALID_DATA_FIELD_IN_REQUEST) == 1))
        {
          struct config_section *section;
          struct config_keyvalue *kv;
          
          section = state_data->sections;
          while (section)
            {
              if (!strcasecmp (section->section_name, "Lan_Conf_Auth"))
                break;
              section = section->next;
            }
          
          /* shouldn't be possible */
          if (!section)
            goto cleanup;
          
          if ((kv = config_find_keyvalue (section,
                                          "Callback_Enable_Auth_Type_OEM_Proprietary")))
            al->callback_level_oem_proprietary = same (kv->value_input, "yes");
          
          if ((kv = config_find_keyvalue (section,
                                          "User_Enable_Auth_Type_OEM_Proprietary")))
            al->user_level_oem_proprietary = same (kv->value_input, "yes");
          
          if ((kv = config_find_keyvalue (section,
                                          "Operator_Enable_Auth_Type_OEM_Proprietary")))
            al->operator_level_oem_proprietary = same (kv->value_input, "yes");
          
          if ((kv = config_find_keyvalue (section,
                                          "Admin_Enable_Auth_Type_OEM_Proprietary")))
            al->admin_level_oem_proprietary = same (kv->value_input, "yes");
          
          if ((kv = config_find_keyvalue (section,
                                          "OEM_Enable_Auth_Type_None")))
            al->oem_level_none = same (kv->value_input, "yes");
          
          if ((kv = config_find_keyvalue (section,
                                          "OEM_Enable_Auth_Type_MD2")))
            al->oem_level_md2 = same (kv->value_input, "yes");
          
          if ((kv = config_find_keyvalue (section,
                                          "OEM_Enable_Auth_Type_MD5")))
            al->oem_level_md5 = same (kv->value_input, "yes");
          
          if ((kv = config_find_keyvalue (section,
                                          "OEM_Enable_Auth_Type_Straight_Password")))
            al->oem_level_straight_password = same (kv->value_input, "yes");
          
          if ((kv = config_find_keyvalue (section,
                                          "OEM_Enable_Auth_Type_OEM_Proprietary")))
            al->oem_level_oem_proprietary = same (kv->value_input, "yes");
          
          if (ipmi_cmd_set_lan_configuration_parameters_authentication_type_enables (state_data->ipmi_ctx,
                                                                                     channel_number,
                                                                                     al->callback_level_none,
                                                                                     al->callback_level_md2,
                                                                                     al->callback_level_md5,
                                                                                     al->callback_level_straight_password,
                                                                                     al->callback_level_oem_proprietary,
                                                                                     al->user_level_none,
                                                                                     al->user_level_md2,
                                                                                     al->user_level_md5,
                                                                                     al->user_level_straight_password,
                                                                                     al->user_level_oem_proprietary,
                                                                                     al->operator_level_none,
                                                                                     al->operator_level_md2,
                                                                                     al->operator_level_md5,
                                                                                     al->operator_level_straight_password,
                                                                                     al->operator_level_oem_proprietary,
                                                                                     al->admin_level_none,
                                                                                     al->admin_level_md2,
                                                                                     al->admin_level_md5,
                                                                                     al->admin_level_straight_password,
                                                                                     al->admin_level_oem_proprietary,
                                                                                     al->oem_level_none,
                                                                                     al->oem_level_md2,
                                                                                     al->oem_level_md5,
                                                                                     al->oem_level_straight_password,
                                                                                     al->oem_level_oem_proprietary,
                                                                                     obj_cmd_rs) < 0)
            {
              if (state_data->prog_data->args->config_args.common_args.debug)
                pstdout_fprintf (state_data->pstate,
                                 stderr,
                                 "ipmi_cmd_set_lan_configuration_parameters_authentication_type_enables: %s\n",
                                 ipmi_ctx_errormsg (state_data->ipmi_ctx));
              
              if (config_is_config_param_non_fatal_error (state_data->ipmi_ctx,
                                                          obj_cmd_rs,
                                                          &ret))
                rv = ret;
              
              goto cleanup;
            }
          
          /* success!! */
          goto out;
        }
      else if (config_is_config_param_non_fatal_error (state_data->ipmi_ctx,
                                                       obj_cmd_rs,
                                                       &ret))
        rv = ret;

      goto cleanup;
    }

 out:
  rv = CONFIG_ERR_SUCCESS;
 cleanup:
  fiid_obj_destroy (obj_cmd_rs);
  return (rv);
}
static config_err_t
_set_alert_policy_table (struct ipmi_pef_config_state_data *state_data,
                         const char *section_name,
                         struct alert_policy_table *apt)
{
  fiid_obj_t obj_cmd_rs = NULL;
  config_err_t rv = CONFIG_ERR_FATAL_ERROR;
  uint8_t alert_policy_entry_number;

  assert (state_data);
  assert (section_name);
  assert (apt);

  alert_policy_entry_number = atoi (section_name + strlen ("Alert_Policy_"));

  if (!(obj_cmd_rs = fiid_obj_create (tmpl_cmd_set_pef_configuration_parameters_rs)))
    {
      pstdout_fprintf (state_data->pstate,
                       stderr,
                       "fiid_obj_create: %s\n",
                       strerror (errno));
      goto cleanup;
    }

  if (ipmi_cmd_set_pef_configuration_parameters_alert_policy_table (state_data->ipmi_ctx,
                                                                    alert_policy_entry_number,
                                                                    apt->policy_type,
                                                                    apt->policy_enabled,
                                                                    apt->policy_number,
                                                                    apt->destination_selector,
                                                                    apt->channel_number,
                                                                    apt->alert_string_set_selector,
                                                                    apt->event_specific_alert_string,
                                                                    obj_cmd_rs) < 0)
    {
      config_err_t ret;

      if (state_data->prog_data->args->config_args.common_args.debug)
        pstdout_fprintf (state_data->pstate,
                         stderr,
                         "ipmi_cmd_set_pef_configuration_parameters_alert_policy_table: %s\n",
                         ipmi_ctx_errormsg (state_data->ipmi_ctx));

      /* IPMI Workaround
       *
       * Fujitsu RX 100 S5
       *
       * Inventec 5441/Dell Xanadu II
       *
       * All fields have to be applied simultaneously, the motherboard
       * does not appear to like configuration of one field of a time,
       * always leading to invalid input errors.  This isn't a
       * compliance issue, but makes it tough to make a portable/good
       * interface.
       */
      if (ipmi_ctx_errnum (state_data->ipmi_ctx) == IPMI_ERR_BAD_COMPLETION_CODE
          && (ipmi_check_completion_code (obj_cmd_rs,
                                          IPMI_COMP_CODE_INVALID_DATA_FIELD_IN_REQUEST) == 1))
        {
          struct config_section *section;
          struct config_keyvalue *kv;
          
          section = state_data->sections;
          while (section)
            {
              if (!strcasecmp (section_name, section->section_name))
                break;
              section = section->next;
            }

          /* shouldn't be possible */
          if (!section)
            goto cleanup;
          
          if ((kv = config_find_keyvalue (section,
                                          "Policy_Type")))
            apt->policy_type = policy_type_number (kv->value_input);

          if ((kv = config_find_keyvalue (section,
                                          "Policy_Enabled")))
            apt->policy_enabled = same (kv->value_input, "yes");

          if ((kv = config_find_keyvalue (section,
                                          "Policy_Number")))
            apt->policy_number = atoi (kv->value_input);

          if ((kv = config_find_keyvalue (section,
                                          "Destination_Selector")))
            apt->destination_selector = atoi (kv->value_input);
          
          if ((kv = config_find_keyvalue (section,
                                          "Channel_Number")))
            apt->channel_number = atoi (kv->value_input);

          if ((kv = config_find_keyvalue (section,
                                          "Alert_String_Set_Selector")))
            apt->alert_string_set_selector = atoi (kv->value_input);
          
          if ((kv = config_find_keyvalue (section,
                                          "Event_Specific_Alert_String")))
            apt->event_specific_alert_string = same (kv->value_input, "yes");

          if (state_data->prog_data->args->config_args.common_args.debug)
            pstdout_fprintf (state_data->pstate,
                             stderr,
                             "ipmi_cmd_set_pef_configuration_parameters_alert_policy_table: attempting workaround\n");

          if (ipmi_cmd_set_pef_configuration_parameters_alert_policy_table (state_data->ipmi_ctx,
                                                                            alert_policy_entry_number,
                                                                            apt->policy_type,
                                                                            apt->policy_enabled,
                                                                            apt->policy_number,
                                                                            apt->destination_selector,
                                                                            apt->channel_number,
                                                                            apt->alert_string_set_selector,
                                                                            apt->event_specific_alert_string,
                                                                            obj_cmd_rs) < 0)
            {
              if (state_data->prog_data->args->config_args.common_args.debug)
                pstdout_fprintf (state_data->pstate,
                                 stderr,
                                 "ipmi_cmd_set_pef_configuration_parameters_alert_policy_table: %s\n",
                                 ipmi_ctx_errormsg (state_data->ipmi_ctx));

              if (config_is_config_param_non_fatal_error (state_data->ipmi_ctx,
                                                          obj_cmd_rs,
                                                          &ret))
                rv = ret;

              goto cleanup;
            }

          /* success */
          goto out;
        }
      else if (config_is_config_param_non_fatal_error (state_data->ipmi_ctx,
                                                       obj_cmd_rs,
                                                       &ret))
        rv = ret;

      goto cleanup;
    }

 out:
  rv = CONFIG_ERR_SUCCESS;
 cleanup:
  fiid_obj_destroy (obj_cmd_rs);
  return (rv);
}
static int
_api_ssif_ipmb_send (ipmi_ctx_t ctx,
		     fiid_obj_t obj_cmd_rq)
{
  struct ipmi_ctx_target target_save;
  uint8_t buf[IPMI_MAX_PKT_LEN];
  fiid_obj_t obj_ipmb_msg_hdr_rq = NULL;
  fiid_obj_t obj_ipmb_msg_rq = NULL;
  fiid_obj_t obj_send_cmd_rs = NULL;
  int len, ret, rv = -1;

  assert (ctx
          && ctx->magic == IPMI_CTX_MAGIC
          && ctx->type == IPMI_DEVICE_SSIF
          && fiid_obj_valid (obj_cmd_rq)
          && fiid_obj_packet_valid (obj_cmd_rq) == 1);

  if (!(obj_ipmb_msg_hdr_rq = fiid_obj_create (tmpl_ipmb_msg_hdr_rq)))
    {
      API_ERRNO_TO_API_ERRNUM (ctx, errno);
      goto cleanup;
    }
  if (!(obj_ipmb_msg_rq = fiid_obj_create (tmpl_ipmb_msg)))
    {
      API_ERRNO_TO_API_ERRNUM (ctx, errno);
      goto cleanup;
    }
  if (!(obj_send_cmd_rs = fiid_obj_create (tmpl_cmd_send_message_rs)))
    {
      API_ERRNO_TO_API_ERRNUM (ctx, errno);
      goto cleanup;
    }

  if (fill_ipmb_msg_hdr (ctx->target.rs_addr,
                         ctx->target.net_fn,
                         ctx->target.lun,
                         IPMI_SLAVE_ADDRESS_BMC,
                         IPMI_BMC_IPMB_LUN_SMS_MSG_LUN,
                         ctx->io.inband.rq_seq,
                         obj_ipmb_msg_hdr_rq) < 0)
    {
      API_ERRNO_TO_API_ERRNUM (ctx, errno);
      goto cleanup;
    }

  if (assemble_ipmi_ipmb_msg (obj_ipmb_msg_hdr_rq,
                              obj_cmd_rq,
                              obj_ipmb_msg_rq,
			      IPMI_INTERFACE_FLAGS_DEFAULT) < 0)
    {
      API_ERRNO_TO_API_ERRNUM (ctx, errno);
      goto cleanup;
    }

  memset (buf, '\0', IPMI_MAX_PKT_LEN);
  if ((len = fiid_obj_get_all (obj_ipmb_msg_rq,
                               buf,
                               IPMI_MAX_PKT_LEN)) < 0)
    {
      API_FIID_OBJECT_ERROR_TO_API_ERRNUM (ctx, obj_ipmb_msg_rq);
      goto cleanup;
    }

  /* send_message will send to the BMC, so clear out target information */
  memcpy (&target_save, &ctx->target, sizeof (target_save));
  ctx->target.channel_number_is_set = 0;
  ctx->target.rs_addr_is_set = 0;
  
  ret = ipmi_cmd_send_message (ctx,
			       target_save.channel_number,
			       IPMI_SEND_MESSAGE_AUTHENTICATION_NOT_REQUIRED,
			       IPMI_SEND_MESSAGE_ENCRYPTION_NOT_REQUIRED,
			       IPMI_SEND_MESSAGE_TRACKING_OPERATION_NO_TRACKING,
			       buf,
			       len,
			       obj_send_cmd_rs);

  /* restore target info */
  memcpy (&ctx->target, &target_save, sizeof (target_save));

  if (ret < 0)
    {
      /* assume these mean can't send message, bad slave address, etc. */
      if (ipmi_check_completion_code (obj_send_cmd_rs, IPMI_COMP_CODE_SEND_MESSAGE_LOST_ARBITRATION) == 1
          || ipmi_check_completion_code (obj_send_cmd_rs, IPMI_COMP_CODE_SEND_MESSAGE_BUS_ERROR) == 1
          || ipmi_check_completion_code (obj_send_cmd_rs, IPMI_COMP_CODE_SEND_MESSAGE_NAK_ON_WRITE) == 1)
        API_SET_ERRNUM (ctx, IPMI_ERR_MESSAGE_TIMEOUT);
      else
        API_BAD_RESPONSE_TO_API_ERRNUM (ctx, obj_send_cmd_rs);
      goto cleanup;
    }

  rv = 0;
 cleanup:
  fiid_obj_destroy (obj_ipmb_msg_hdr_rq);
  fiid_obj_destroy (obj_ipmb_msg_rq);
  fiid_obj_destroy (obj_send_cmd_rs);
  return (rv);
}
static int
_api_ssif_ipmb_recv (ipmi_ctx_t ctx,
		     fiid_obj_t obj_ipmb_msg_hdr_rs,
		     fiid_obj_t obj_ipmb_msg_trlr,
		     fiid_obj_t obj_cmd_rs)
{
  struct ipmi_ctx_target target_save;
  uint8_t buf[IPMI_MAX_PKT_LEN];
  fiid_obj_t obj_ipmb_msg_rs = NULL;
  fiid_obj_t obj_get_cmd_rs = NULL;
  int len, ret, rv = -1;
  unsigned int intf_flags = IPMI_INTERFACE_FLAGS_DEFAULT;

  assert (ctx
          && ctx->magic == IPMI_CTX_MAGIC
          && ctx->type == IPMI_DEVICE_SSIF
          && fiid_obj_valid (obj_ipmb_msg_hdr_rs)
          && fiid_obj_valid (obj_ipmb_msg_trlr)
          && fiid_obj_valid (obj_cmd_rs));

  if (ctx->flags & IPMI_FLAGS_NO_LEGAL_CHECK)
    intf_flags |= IPMI_INTERFACE_FLAGS_NO_LEGAL_CHECK;

  if (!(obj_ipmb_msg_rs = fiid_obj_create (tmpl_ipmb_msg)))
    {
      API_ERRNO_TO_API_ERRNUM (ctx, errno);
      goto cleanup;
    }
  if (!(obj_get_cmd_rs = fiid_obj_create (tmpl_cmd_get_message_rs)))
    {
      API_ERRNO_TO_API_ERRNUM (ctx, errno);
      goto cleanup;
    }
  
  /* get_message will send to the BMC, so clear out target information */
  memcpy (&target_save, &ctx->target, sizeof (target_save));
  ctx->target.channel_number_is_set = 0;
  ctx->target.rs_addr_is_set = 0;
  
  ret = ipmi_cmd_get_message (ctx, obj_get_cmd_rs);

  /* restore target info */
  memcpy (&ctx->target, &target_save, sizeof (target_save));

  if (ret < 0)
    {
      if (ipmi_check_completion_code (obj_get_cmd_rs, IPMI_COMP_CODE_GET_MESSAGE_DATA_NOT_AVAILABLE) == 1)
        API_SET_ERRNUM (ctx, IPMI_ERR_MESSAGE_TIMEOUT);
      else
        API_BAD_RESPONSE_TO_API_ERRNUM (ctx, obj_get_cmd_rs);
      goto cleanup;
    }

  if ((len = fiid_obj_get_data (obj_get_cmd_rs,
                                "message_data",
                                buf,
                                IPMI_MAX_PKT_LEN)) < 0)
    {
      API_FIID_OBJECT_ERROR_TO_API_ERRNUM (ctx, obj_get_cmd_rs);
      goto cleanup;
    }

  if (fiid_obj_set_all (obj_ipmb_msg_rs,
                        buf,
                        len) < 0)
    {
      API_FIID_OBJECT_ERROR_TO_API_ERRNUM (ctx, obj_ipmb_msg_rs);
      goto cleanup;
    }

  if (unassemble_ipmi_ipmb_msg (obj_ipmb_msg_rs,
                                obj_ipmb_msg_hdr_rs,
                                obj_cmd_rs,
                                obj_ipmb_msg_trlr,
				intf_flags) < 0)
    {
      API_ERRNO_TO_API_ERRNUM (ctx, errno);
      goto cleanup;
    }

  rv = 0;
 cleanup:
  fiid_obj_destroy (obj_ipmb_msg_rs);
  fiid_obj_destroy (obj_get_cmd_rs);
  return (rv);
}
static ipmi_config_err_t
_set_power_limit (ipmi_config_state_data_t *state_data,
                  const char *section_name,
                  struct get_power_limit_data *gpld,
                  int no_set_power_limit_flag)
{
  fiid_obj_t obj_cmd_rs = NULL;
  ipmi_config_err_t rv = IPMI_CONFIG_ERR_FATAL_ERROR;

  assert (state_data);
  assert (section_name);
  assert (gpld);

  /* IPMI Workaround/Interpretation
   *
   * The DCMI spec indicates a potential completion code for the
   * "Get Power Limit" command as "No Set Power Limit" (0x80).
   * FreeIPMI originally interpreted this to mean the "Set Power
   * Limit" command was not available.  Atleast one vendor
   * interpreted this to mean "No Power Limit Set".  One can
   * consider this an English interpretation issue of 'No set
   * POWER LIMIT' vs. 'No SET POWER LIMIT' (i.e. is "set" a verb
   * or part of a proper noun referencing the DCMI command).
   * Confounding this issue is the fact that the example
   * implementation in Intel's DCMItool implements the former,
   * while the DCMI Conformance test suite implements the latter.
   * In addition to this, with the latter interpretation, it need
   * not be an indication of an error, but rather a flag.  So the
   * rest of the packet can be completely full of legitimate data.
   * 
   * So we will do the following.
   *
   * If the "No Set Power Limit" completion code is returned and 
   * we were able to read all of the fields, _get_power_limit() will
   * return normally, so we don't need to worry about this case. 
   *
   * If the "No Set Power Limit", completion code is returned and
   * we were *not* able to read all of the fields, we won't have
   * values from "Get Power Limit" and won't know how to do the
   * configuration properly in "Set Power Limit".  So we will
   * require that the user input all fields for "Set Power Limit".
   */

  if (no_set_power_limit_flag)
    {
      struct ipmi_config_section *section;
      struct ipmi_config_keyvalue *kv;

      section = state_data->sections;
      while (section)
        {
          if (!strcasecmp (section_name, section->section_name))
            break;
          section = section->next;
        }

      /* shouldn't be possible */
      if (!section)
        goto cleanup;

      if ((kv = ipmi_config_find_keyvalue (section, "Policy_Type")))
        gpld->power_limit_requested = atoi (kv->value_input);

      if ((kv = ipmi_config_find_keyvalue (section, "Policy_Enabled")))
        gpld->correction_time_limit = strtoul (kv->value_input, NULL, 0);

      if ((kv = ipmi_config_find_keyvalue (section, "Management_Application_Statistics_Sampling_Period")))
        gpld->management_application_statistics_sampling_period = atoi (kv->value_input);

      if ((kv = ipmi_config_find_keyvalue (section, "Exception_Actions")))
        {
          int num = exception_actions_number (kv->value_input);

          if (num < 0)
            /* previously checked for correctness, so no error check */
            gpld->exception_actions = strtol (kv->value_input, NULL, 0);
          else
            gpld->exception_actions = num;
        }
    }

  if (!(obj_cmd_rs = fiid_obj_create (tmpl_cmd_dcmi_set_power_limit_rs)))
    {
      pstdout_fprintf (state_data->pstate,
                       stderr,
                       "fiid_obj_create: %s\n",
                       strerror (errno));
      goto cleanup;
    }
  
  if (ipmi_cmd_dcmi_set_power_limit (state_data->ipmi_ctx,
                                     gpld->exception_actions,
                                     gpld->power_limit_requested,
                                     gpld->correction_time_limit,
                                     gpld->management_application_statistics_sampling_period,
                                     obj_cmd_rs) < 0)
    {
      ipmi_config_err_t ret;

      if ((ipmi_check_completion_code (obj_cmd_rs,
                                       IPMI_COMP_CODE_DCMI_POWER_LIMIT_OUT_OF_RANGE) == 1)
          || (ipmi_check_completion_code (obj_cmd_rs,
                                              IPMI_COMP_CODE_DCMI_CORRECTION_TIME_OUT_OF_RANGE) == 1)
          || (ipmi_check_completion_code (obj_cmd_rs,
                                          IPMI_COMP_CODE_DCMI_STATISTICS_REPORTING_PERIOD_OUT_OF_RANGE) == 1))
        rv = IPMI_CONFIG_ERR_NON_FATAL_ERROR;
      else
        {
          if (ipmi_config_param_errnum_is_non_fatal (state_data,
                                                     obj_cmd_rs,
                                                     &ret))
            rv = ret;
        }

      if (rv == IPMI_CONFIG_ERR_FATAL_ERROR
          || state_data->prog_data->args->common_args.debug)
        {
          if (ipmi_ctx_errnum (state_data->ipmi_ctx) == IPMI_ERR_BAD_COMPLETION_CODE
              && ipmi_check_completion_code (obj_cmd_rs,
                                             IPMI_COMP_CODE_DCMI_POWER_LIMIT_OUT_OF_RANGE) == 1)
            pstdout_fprintf (state_data->pstate,
                             stderr,
                             "ipmi_cmd_dcmi_set_power_limit: %s\n",
                             IPMI_COMP_CODE_DCMI_POWER_LIMIT_OUT_OF_RANGE_STR);
          else if (ipmi_ctx_errnum (state_data->ipmi_ctx) == IPMI_ERR_BAD_COMPLETION_CODE
                   && ipmi_check_completion_code (obj_cmd_rs,
                                                  IPMI_COMP_CODE_DCMI_CORRECTION_TIME_OUT_OF_RANGE) == 1)
            pstdout_fprintf (state_data->pstate,
                             stderr,
                             "ipmi_cmd_dcmi_set_power_limit: %s\n",
                             IPMI_COMP_CODE_DCMI_CORRECTION_TIME_OUT_OF_RANGE_STR);
          else if (ipmi_ctx_errnum (state_data->ipmi_ctx) == IPMI_ERR_BAD_COMPLETION_CODE
                   && ipmi_check_completion_code (obj_cmd_rs,
                                                  IPMI_COMP_CODE_DCMI_STATISTICS_REPORTING_PERIOD_OUT_OF_RANGE) == 1)
            pstdout_fprintf (state_data->pstate,
                             stderr,
                             "ipmi_cmd_dcmi_set_power_limit: %s\n",
                             IPMI_COMP_CODE_DCMI_STATISTICS_REPORTING_PERIOD_OUT_OF_RANGE_STR);
          else
            pstdout_fprintf (state_data->pstate,
                             stderr,
                             "ipmi_cmd_dcmi_set_power_limit: %s\n",
                             ipmi_ctx_errormsg (state_data->ipmi_ctx));
        }

      goto cleanup;
    }

  rv = IPMI_CONFIG_ERR_SUCCESS;
 cleanup:
  fiid_obj_destroy (obj_cmd_rs);
  return (rv);
}
static ipmi_config_err_t
_get_power_limit (ipmi_config_state_data_t *state_data,
                  struct get_power_limit_data *gpld,
                  int *no_set_power_limit_flag)
{
  fiid_obj_t obj_cmd_rs = NULL;
  uint64_t val;
  int no_set_power_limit_error_flag = 0;
  ipmi_config_err_t rv = IPMI_CONFIG_ERR_FATAL_ERROR;

  assert (state_data);
  assert (gpld);

  if (no_set_power_limit_flag)
    (*no_set_power_limit_flag) = 0;

  if (!(obj_cmd_rs = fiid_obj_create (tmpl_cmd_dcmi_get_power_limit_rs)))
    {
      pstdout_fprintf (state_data->pstate,
                       stderr,
                       "fiid_obj_create: %s",
                       strerror (errno));
      goto cleanup;
    }

  /* IPMI Workaround/Interpretation
   *
   * The DCMI spec indicates a potential completion code for the "Get
   * Power Limit" command as "No Set Power Limit" (0x80).  FreeIPMI
   * originally interpreted this to mean the "Set Power Limit" command
   * was not available.  Atleast one vendor interpreted this to mean
   * "No Power Limit Set".  One can consider this an English
   * interpretation issue of 'No set POWER LIMIT' vs. 'No SET POWER
   * LIMIT' (i.e. is "set" a verb or part of a proper noun referencing
   * the DCMI command).  Confounding this issue is the fact that the
   * example implementation in Intel's DCMItool implements the former,
   * while the DCMI Conformance test suite implements the latter.  In
   * addition to this, with the latter interpretation, it need not be
   * an indication of an error, but rather a flag.  So the rest of the
   * packet can be completely full of legitimate data.
   *
   * So how do we handle this?
   *
   * If we hit "No Set Power Limit", try to read data.  If we can't
   * read data (b/c it's not set), fail out, but preserve the "No Set
   * Power Limit" error message.
   */

  if (ipmi_cmd_dcmi_get_power_limit (state_data->ipmi_ctx,
                                     obj_cmd_rs) < 0)
    {
      ipmi_config_err_t ret;

      if (ipmi_ctx_errnum (state_data->ipmi_ctx) == IPMI_ERR_BAD_COMPLETION_CODE
          && ipmi_check_completion_code (obj_cmd_rs,
                                         IPMI_COMP_CODE_DCMI_NO_SET_POWER_LIMIT) == 1)
        {
          if (state_data->prog_data->args->common_args.debug)
            pstdout_fprintf (state_data->pstate,
                             stderr,
                             "ipmi_cmd_dcmi_get_power_limit: %s",
                             IPMI_COMP_CODE_DCMI_NO_SET_POWER_LIMIT_STR);

          if (no_set_power_limit_flag)
            (*no_set_power_limit_flag) = 1;
 
          no_set_power_limit_error_flag++;
          goto read_data;
        }

      if (ipmi_config_param_errnum_is_non_fatal (state_data,
                                                 obj_cmd_rs,
                                                 &ret))
        rv = ret;

      if (rv == IPMI_CONFIG_ERR_FATAL_ERROR
          || state_data->prog_data->args->common_args.debug)
        pstdout_fprintf (state_data->pstate,
                         stderr,
                         "ipmi_cmd_get_pef_configuration_parameters_event_filter_table: %s\n",
                         ipmi_ctx_errormsg (state_data->ipmi_ctx));

      goto cleanup;
    }

 read_data:

  if (FIID_OBJ_GET (obj_cmd_rs,
                    "exception_actions",
                    &val) < 0)
    {
      if (!no_set_power_limit_error_flag
          || fiid_obj_errnum (obj_cmd_rs) != FIID_ERR_DATA_NOT_AVAILABLE)
        pstdout_fprintf (state_data->pstate,
                         stderr,
                         "fiid_obj_get: 'exception_actions': %s",
                         fiid_obj_errormsg (obj_cmd_rs));

      if (no_set_power_limit_error_flag)
        rv = IPMI_CONFIG_ERR_NON_FATAL_ERROR;

      goto cleanup;
    }
  gpld->exception_actions = val;
  
  if (FIID_OBJ_GET (obj_cmd_rs,
                    "power_limit_requested",
                    &val) < 0)
    {
      if (!no_set_power_limit_error_flag
          || fiid_obj_errnum (obj_cmd_rs) != FIID_ERR_DATA_NOT_AVAILABLE)
        pstdout_fprintf (state_data->pstate,
                         stderr,
                         "fiid_obj_get: 'power_limit_requested': %s",
                         fiid_obj_errormsg (obj_cmd_rs));

      if (no_set_power_limit_error_flag)
        rv = IPMI_CONFIG_ERR_NON_FATAL_ERROR;

      goto cleanup;
    }
  gpld->power_limit_requested = val;

  if (FIID_OBJ_GET (obj_cmd_rs,
                    "correction_time_limit",
                    &val) < 0)
    {
      if (!no_set_power_limit_error_flag
          || fiid_obj_errnum (obj_cmd_rs) != FIID_ERR_DATA_NOT_AVAILABLE)
        pstdout_fprintf (state_data->pstate,
                         stderr,
                         "fiid_obj_get: 'correction_time_limit': %s",
                         fiid_obj_errormsg (obj_cmd_rs));

      if (no_set_power_limit_error_flag)
        rv = IPMI_CONFIG_ERR_NON_FATAL_ERROR;

      goto cleanup;
    }
  gpld->correction_time_limit = val;

  if (FIID_OBJ_GET (obj_cmd_rs,
                    "management_application_statistics_sampling_period",
                    &val) < 0)
    {
      if (!no_set_power_limit_error_flag
          || fiid_obj_errnum (obj_cmd_rs) != FIID_ERR_DATA_NOT_AVAILABLE)
        pstdout_fprintf (state_data->pstate,
                         stderr,
                         "fiid_obj_get: 'management_application_statistics_sampling_period': %s",
                         fiid_obj_errormsg (obj_cmd_rs));

      if (no_set_power_limit_error_flag)
        rv = IPMI_CONFIG_ERR_NON_FATAL_ERROR;

      goto cleanup;
    }
  gpld->management_application_statistics_sampling_period = val;

  rv = IPMI_CONFIG_ERR_SUCCESS;
 cleanup:
  fiid_obj_destroy (obj_cmd_rs);
  return (rv);
}
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
_sensor_reading_corner_case_checks (ipmi_sensor_read_ctx_t ctx,
                                    fiid_obj_t obj_cmd_rs)
{
  assert (ctx);
  assert (ctx->magic == IPMI_SENSOR_READ_CTX_MAGIC);
  assert (obj_cmd_rs);

  if (ipmi_check_completion_code (obj_cmd_rs,
                                  IPMI_COMP_CODE_NODE_BUSY) == 1)
    {
      SENSOR_READ_SET_ERRNUM (ctx, IPMI_SENSOR_READ_ERR_NODE_BUSY);
      return (-1);
    }
  /* IPMI Workaround
   *
   * achu: Error codes found on motherboards that strongly suggest
   * "sensor not available".  See comments in
   * freeipmi-bugs-issues-and-workarounds.txt for why I think this is
   * a workaround and not an "ok" set of errors.
   */
  else if ((ipmi_check_completion_code (obj_cmd_rs,
                                        IPMI_COMP_CODE_REQUESTED_SENSOR_DATA_OR_RECORD_NOT_PRESENT) == 1)
           || (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_PARAMETER_OUT_OF_RANGE) == 1)
           || (ipmi_check_completion_code (obj_cmd_rs,
                                           IPMI_COMP_CODE_INVALID_DATA_FIELD_IN_REQUEST) == 1)
           || (ipmi_check_completion_code (obj_cmd_rs, 
                                           IPMI_COMP_CODE_COMMAND_RESPONSE_COULD_NOT_BE_PROVIDED) == 1)
           || (ipmi_check_completion_code (obj_cmd_rs,
                                           IPMI_COMP_CODE_REQUEST_PARAMETER_NOT_SUPPORTED) == 1)
           || (ipmi_check_completion_code (obj_cmd_rs,
                                           IPMI_COMP_CODE_DESTINATION_UNAVAILABLE) == 1))
    {
      SENSOR_READ_SET_ERRNUM (ctx, IPMI_SENSOR_READ_ERR_SENSOR_READING_UNAVAILABLE);
      return (-1);
    }
  else if ((ipmi_check_completion_code (obj_cmd_rs,
                                        IPMI_COMP_CODE_UNSPECIFIED_ERROR) == 1))
    {
      uint64_t val; 
      int flag;

      /* IPMI Workaround
       *
       * Discovered on Sun Blade x6250
       *
       * For some reason, some sensors can return this error code
       * (0xFF).  However, it appears to be an invalid error response
       * b/c the sensor properly reports that the sensor reading is
       * not available or that scanning is diabled.  So if the sensor
       * reports that it is unavailable, we'll report an error code
       * slightly more appropriate.
       *
       * Note, I do not handle this identically to the corner case
       * checks above.  Those completion codes strongly suggest that a
       * sensor is not available.  The error code "Unspecified Error"
       * could mean anything.
       */
      
      if ((flag = fiid_obj_get (obj_cmd_rs,
                                "reading_state",
                                &val)) < 0)
        {
          SENSOR_READ_FIID_OBJECT_ERROR_TO_SENSOR_READ_ERRNUM (ctx, obj_cmd_rs);
          return (-1);
        }
      
      if (flag && val == IPMI_SENSOR_READING_STATE_UNAVAILABLE)
        {
          SENSOR_READ_SET_ERRNUM (ctx, IPMI_SENSOR_READ_ERR_SENSOR_READING_UNAVAILABLE);
          return (-1);
        }
      
      if (!(ctx->flags & IPMI_SENSOR_READ_FLAGS_IGNORE_SCANNING_DISABLED))
        {
          if ((flag = fiid_obj_get (obj_cmd_rs,
                                    "sensor_scanning",
                                    &val)) < 0)
            {
              SENSOR_READ_FIID_OBJECT_ERROR_TO_SENSOR_READ_ERRNUM (ctx, obj_cmd_rs);
              return (-1);
            }
          
          if (flag && val == IPMI_SENSOR_SCANNING_ON_THIS_SENSOR_DISABLE)
            {
              SENSOR_READ_SET_ERRNUM (ctx, IPMI_SENSOR_READ_ERR_SENSOR_SCANNING_DISABLED);
              return (-1);
            }
        }

      /* else fall through like normal */
    }

  return (0);
}
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);
}