config_err_t
create_section_name (ipmi_sensors_config_state_data_t *state_data,
                     char *section_name,
                     unsigned int section_name_len)
{
  char id_string[IPMI_SDR_MAX_ID_STRING_LENGTH + 1];
  uint16_t record_id;
  config_err_t rv = CONFIG_ERR_FATAL_ERROR;
  config_err_t ret;

  assert (state_data);
  assert (section_name);
  assert (section_name_len);

  memset (section_name, '\0', section_name_len);
  memset (id_string, '\0', IPMI_SDR_MAX_ID_STRING_LENGTH + 1);

  if (ipmi_sdr_parse_record_id_and_type (state_data->sdr_ctx,
					 NULL,
					 0,
                                         &record_id,
                                         NULL) < 0)
    {
      pstdout_fprintf (state_data->pstate,
                       stderr,
                       "ipmi_sdr_parse_record_id_and_type: %s\n",
                       ipmi_sdr_ctx_errormsg (state_data->sdr_ctx));
      goto cleanup;
    }

  if (ipmi_sdr_parse_id_string (state_data->sdr_ctx,
				NULL,
				0,
                                id_string,
                                IPMI_SDR_MAX_ID_STRING_LENGTH) < 0)
    {
      pstdout_fprintf (state_data->pstate,
                       stderr,
                       "ipmi_sdr_parse_id_string: %s\n",
                       ipmi_sdr_ctx_errormsg (state_data->sdr_ctx));
      goto cleanup;
    }

  if ((ret = convert_id_string (state_data, id_string)) != CONFIG_ERR_SUCCESS)
    {
      if (state_data->prog_data->args->config_args.common_args.debug)
        pstdout_fprintf (state_data->pstate,
                         stderr,
                         "convert_id_string: %s\n",
                         strerror (errno));
      rv = ret;
      goto cleanup;
    }

  /* We will name sections by record_id then name, since id_strings
   * could be identical.
   */
  if (strlen (id_string) > 0)
    snprintf (section_name,
              CONFIG_MAX_SECTION_NAME_LEN,
              "%u_%s",
              record_id,
              id_string);
  else
    /* I guess its conceivable the sensor won't have a name, so we
     * make one up.
     */
    snprintf (section_name,
              CONFIG_MAX_SECTION_NAME_LEN,
              "%u_%s",
              record_id,
              "Unknown_Sensor_Name");

  rv = CONFIG_ERR_SUCCESS;
 cleanup:
  return (rv);
}
Пример #2
0
int
ipmi_sdr_parse_sensor_name (ipmi_sdr_ctx_t ctx,
			    const void *sdr_record,
			    unsigned int sdr_record_len,
			    uint8_t sensor_number,
			    unsigned int flags,
			    char *buf,
			    unsigned int buflen)
{
  char id_string[IPMI_SDR_MAX_ID_STRING_LENGTH + 1];
  char device_id_string[IPMI_SDR_MAX_DEVICE_ID_STRING_LENGTH + 1];
  char *id_string_ptr = NULL;
  uint8_t record_type;
  unsigned int flags_mask = (IPMI_SDR_SENSOR_NAME_FLAGS_IGNORE_SHARED_SENSORS);

  if (!ctx || ctx->magic != IPMI_SDR_CTX_MAGIC)
    {
      ERR_TRACE (ipmi_sdr_ctx_errormsg (ctx), ipmi_sdr_ctx_errnum (ctx));
      return (-1);
    }

  if (ctx->operation != IPMI_SDR_OPERATION_READ_CACHE)
    {
      SDR_SET_ERRNUM (ctx, IPMI_SDR_ERR_CACHE_READ_INITIALIZATION);
      return (-1);
    }

  if (((sdr_record_len && !sdr_record_len)
       || (!sdr_record && sdr_record_len))
      || (flags & ~flags_mask)
      || !buf
      || !buflen)
    {
      SDR_SET_ERRNUM (ctx, IPMI_SDR_ERR_PARAMETERS);
      return (-1);
    }

  memset (buf, '\0', buflen);

  if (ipmi_sdr_parse_record_id_and_type (ctx,
					 sdr_record,
					 sdr_record_len,
                                         NULL,
                                         &record_type) < 0)
    return (-1);

  if (record_type == IPMI_SDR_FORMAT_FULL_SENSOR_RECORD
      || record_type == IPMI_SDR_FORMAT_COMPACT_SENSOR_RECORD
      || record_type == IPMI_SDR_FORMAT_EVENT_ONLY_RECORD)
    {
      memset (id_string, '\0', IPMI_SDR_MAX_ID_STRING_LENGTH + 1);

      if (ipmi_sdr_parse_id_string (ctx,
				    sdr_record,
				    sdr_record_len,
				    id_string,
                                    IPMI_SDR_MAX_ID_STRING_LENGTH) < 0)
	return (-1);

      id_string_ptr = id_string;
    }
  else if (record_type == IPMI_SDR_FORMAT_GENERIC_DEVICE_LOCATOR_RECORD
	   || record_type == IPMI_SDR_FORMAT_FRU_DEVICE_LOCATOR_RECORD
           || record_type == IPMI_SDR_FORMAT_MANAGEMENT_CONTROLLER_DEVICE_LOCATOR_RECORD)
    {
      memset (device_id_string, '\0', IPMI_SDR_MAX_DEVICE_ID_STRING_LENGTH + 1);

      if (ipmi_sdr_parse_device_id_string (ctx,
					   sdr_record,
					   sdr_record_len,
                                           device_id_string,
                                           IPMI_SDR_MAX_DEVICE_ID_STRING_LENGTH) < 0)
	return (-1);
      
      id_string_ptr = device_id_string;
    }
  else
    {
      SDR_SET_ERRNUM (ctx, IPMI_SDR_ERR_PARSE_INVALID_SDR_RECORD);
      return (-1);
    }

  /* special case if sensor sharing is involved */
  if ((record_type == IPMI_SDR_FORMAT_COMPACT_SENSOR_RECORD
       || record_type == IPMI_SDR_FORMAT_EVENT_ONLY_RECORD)
      && !(flags & IPMI_SDR_SENSOR_NAME_FLAGS_IGNORE_SHARED_SENSORS))
    {
      if (_get_shared_sensor_name (ctx,
				   sdr_record,
				   sdr_record_len,
				   sensor_number,
				   id_string_ptr,
				   buf,
				   buflen) < 0)
	return (-1);
    }
  else
    snprintf (buf,
	      buflen,
	      "%s",
	      id_string_ptr);

  return (0);
}
Пример #3
0
int
ipmi_sdr_parse_entity_sensor_name (ipmi_sdr_ctx_t ctx,
				   const void *sdr_record,
				   unsigned int sdr_record_len,
				   uint8_t sensor_number,
				   unsigned int flags,
				   char *buf,
				   unsigned int buflen)
{
  char id_string[IPMI_SDR_MAX_ID_STRING_LENGTH + 1];
  char device_id_string[IPMI_SDR_MAX_DEVICE_ID_STRING_LENGTH + 1];
  char entity_name_buf[IPMI_SDR_ENTITY_NAME_BUFLEN + 1];
  char *id_string_ptr = NULL;
  uint8_t entity_id, entity_instance, entity_instance_type;
  const char *entity_id_str;
  uint8_t record_type;
  unsigned int flags_mask = (IPMI_SDR_SENSOR_NAME_FLAGS_IGNORE_SHARED_SENSORS
			     | IPMI_SDR_SENSOR_NAME_FLAGS_ALWAYS_OUTPUT_INSTANCE_NUMBER);

  if (!ctx || ctx->magic != IPMI_SDR_CTX_MAGIC)
    {
      ERR_TRACE (ipmi_sdr_ctx_errormsg (ctx), ipmi_sdr_ctx_errnum (ctx));
      return (-1);
    }

  if (ctx->operation != IPMI_SDR_OPERATION_READ_CACHE)
    {
      SDR_SET_ERRNUM (ctx, IPMI_SDR_ERR_CACHE_READ_INITIALIZATION);
      return (-1);
    }

  if (((sdr_record_len && !sdr_record_len)
       || (!sdr_record && sdr_record_len))
      || (flags & ~flags_mask)
      || !buf
      || !buflen)
    {
      SDR_SET_ERRNUM (ctx, IPMI_SDR_ERR_PARAMETERS);
      return (-1);
    }

  memset (buf, '\0', buflen);
  memset (entity_name_buf, '\0', IPMI_SDR_ENTITY_NAME_BUFLEN + 1);

  if (ipmi_sdr_parse_record_id_and_type (ctx,
					 sdr_record,
					 sdr_record_len,
                                         NULL,
                                         &record_type) < 0)
    return (-1);

  if (record_type == IPMI_SDR_FORMAT_FULL_SENSOR_RECORD
      || record_type == IPMI_SDR_FORMAT_COMPACT_SENSOR_RECORD
      || record_type == IPMI_SDR_FORMAT_EVENT_ONLY_RECORD)
    {
      memset (id_string, '\0', IPMI_SDR_MAX_ID_STRING_LENGTH + 1);

      if (ipmi_sdr_parse_id_string (ctx,
				    sdr_record,
				    sdr_record_len,
				    id_string,
                                    IPMI_SDR_MAX_ID_STRING_LENGTH) < 0)
	return (-1);

      id_string_ptr = id_string;
    }
  else if (record_type == IPMI_SDR_FORMAT_GENERIC_DEVICE_LOCATOR_RECORD
           || record_type == IPMI_SDR_FORMAT_MANAGEMENT_CONTROLLER_DEVICE_LOCATOR_RECORD)
    {
      memset (device_id_string, '\0', IPMI_SDR_MAX_DEVICE_ID_STRING_LENGTH + 1);

      if (ipmi_sdr_parse_device_id_string (ctx,
					   sdr_record,
					   sdr_record_len,
                                           device_id_string,
                                           IPMI_SDR_MAX_DEVICE_ID_STRING_LENGTH) < 0)
	return (-1);
      
      id_string_ptr = device_id_string;
    }
  else
    {
      SDR_SET_ERRNUM (ctx, IPMI_SDR_ERR_PARSE_INVALID_SDR_RECORD);
      return (-1);
    }

  if (ipmi_sdr_parse_entity_id_instance_type (ctx,
					      sdr_record,
					      sdr_record_len,
                                              &entity_id,
                                              &entity_instance,
                                              &entity_instance_type) < 0)
    return (-1);

  /* Table 39-1
   *
   * "It is recommended that console software subtract 60h when
   * presenting device-relative Entity Instance values, and present
   * the Entity Instance number along with an ID for the device
   * providing the interface to the entity."
   *
   * achu: For the time being we do not output the device providing
   * the interface, only the right instance number.  Adjust later if
   * necessary.
   */

  if (IPMI_ENTITY_INSTANCE_DEVICE_RELATIVE (entity_instance))
    entity_instance -= IPMI_ENTITY_INSTANCE_DEVICE_RELATIVE_MIN;

  entity_id_str = ipmi_get_entity_id_string (entity_id);

  /* a few special cases, for entity_ids are special, the vendor has
   * specifically stated there is no "entity" associated with this sdr
   * record
   */
  if (entity_id == IPMI_ENTITY_ID_UNSPECIFIED
      || entity_id == IPMI_ENTITY_ID_OTHER
      || entity_id == IPMI_ENTITY_ID_UNKNOWN)
    snprintf (buf,
	      buflen,
	      "%s",
	      id_string_ptr);
  else
    {
      if (ipmi_sdr_stats_compile (ctx) < 0)
	return (-1);

      if (ipmi_sdr_stats_entity_instance_unique (ctx, entity_id) > 1)
        {
          /* special case if sensor sharing is involved */
          if ((record_type == IPMI_SDR_FORMAT_COMPACT_SENSOR_RECORD
               || record_type == IPMI_SDR_FORMAT_EVENT_ONLY_RECORD)
              && !(flags & IPMI_SDR_SENSOR_NAME_FLAGS_IGNORE_SHARED_SENSORS))
            {
	      uint8_t share_count;
	      uint8_t entity_instance_sharing;
	      char sensor_name_buf[IPMI_SDR_MAX_SENSOR_NAME_LENGTH + 1];

	      if (ipmi_sdr_parse_sensor_record_sharing (ctx,
							sdr_record,
							sdr_record_len,
							&share_count,
							NULL,
							NULL,
							&entity_instance_sharing) < 0)
		return (-1);
      
	      if (share_count > 1
		  && entity_instance_sharing == IPMI_SDR_ENTITY_INSTANCE_INCREMENTS_FOR_EACH_SHARED_RECORD)
		{
		  uint8_t sensor_number_base;
      
		  if (ipmi_sdr_parse_sensor_number (ctx,
						    sdr_record,
						    sdr_record_len,
						    &sensor_number_base) < 0)
		    return (-1);
      
		  /* I guess it's a bug if the sensor number passed in is bad */
		  if (sensor_number >= sensor_number_base)
		    entity_instance += (sensor_number - sensor_number_base);
		  else
		    goto fallthrough;
		}

	      memset (sensor_name_buf, '\0', IPMI_SDR_MAX_SENSOR_NAME_LENGTH + 1);
	      
	      if (_get_shared_sensor_name (ctx,
					   sdr_record,
					   sdr_record_len,
					   sensor_number,
					   id_string_ptr,
					   sensor_name_buf,
					   IPMI_SDR_MAX_SENSOR_NAME_LENGTH) < 0)
		return (-1);

	      snprintf (entity_name_buf,
			IPMI_SDR_ENTITY_NAME_BUFLEN,
			"%s %u",
			entity_id_str,
			entity_instance);

	      /* In odd chance the strings end up identical */
	      if (!strcasecmp (entity_name_buf, sensor_name_buf))
		snprintf (buf,
			  buflen,
			  "%s",
			  sensor_name_buf);
	      else
		snprintf (buf,
			  buflen,
			  "%s %s",
			  entity_name_buf,
			  sensor_name_buf);
	    }
	  else
	    {
	    fallthrough:
	      snprintf (entity_name_buf,
			IPMI_SDR_ENTITY_NAME_BUFLEN,
			"%s %u",
			entity_id_str,
			entity_instance);
	      
	      /* In odd chance the strings end up identical */
	      if (!strcasecmp (entity_name_buf, id_string_ptr))
		snprintf (buf,
			  buflen,
			  "%s",
			  id_string_ptr);
	      else
		snprintf (buf,
			  buflen,
			  "%s %s",
			  entity_name_buf,
			  id_string_ptr);
	    }
	}
      else
	{
	  if (flags & IPMI_SDR_SENSOR_NAME_FLAGS_ALWAYS_OUTPUT_INSTANCE_NUMBER)
	    {
	      snprintf (entity_name_buf,
			IPMI_SDR_ENTITY_NAME_BUFLEN,
			"%s %u",
			entity_id_str,
			entity_instance);
	      
	      /* In odd chance the strings end up identical */
	      if (!strcasecmp (entity_name_buf, id_string_ptr))
		snprintf (buf,
			  buflen,
			  "%s",
			  id_string_ptr);
	      else
		snprintf (buf,
			  buflen,
			  "%s %s",
			  entity_name_buf,
			  id_string_ptr);
	    }
	  else
	    {
	      /* In odd chance the strings end up identical */
	      if (!strcasecmp (entity_id_str, id_string_ptr))
		snprintf (buf,
			  buflen,
			  "%s",
			  id_string_ptr);
	      else
		snprintf (buf,
			  buflen,
			  "%s %s",
			  entity_id_str,
			  id_string_ptr);
	    }
	}
    }

  return (0);
}
Пример #4
0
static int
_get_led_sdr_callback (ipmi_sdr_ctx_t sdr_ctx,
		       uint8_t record_type,
		       const void *sdr_record,
		       unsigned int sdr_record_len,
		       void *arg)
{
  struct ipmi_oem_ibm_get_led_sdr_callback *sdr_callback_arg;
  ipmi_oem_state_data_t *state_data;
  uint8_t bytes_rq[IPMI_OEM_MAX_BYTES];
  uint8_t bytes_rs[IPMI_OEM_MAX_BYTES];
  int rs_len;
  uint8_t oem_data_buf[IPMI_SDR_MAX_RECORD_LENGTH];
  int oem_data_buf_len;
  uint16_t record_id;
  char fmt[IPMI_OEM_FMT_BUFLEN + 1];
  char led_name[IPMI_OEM_IBM_LED_NAME_BUFLEN + 1];
  char led_pointer_name[IPMI_OEM_IBM_LED_NAME_BUFLEN + 1];
  char id_string[IPMI_OEM_IBM_LED_ID_STRING_BUFLEN + 1];
  char led_info[IPMI_OEM_IBM_LED_INFO_BUFLEN + 1];
  char *led_state_str = NULL;
  uint8_t sensor_type;
  uint8_t led_id_ls;
  uint8_t led_id_ms;
  uint16_t led_id;
  uint8_t led_state;
  uint8_t led_active_type;
  uint16_t led_pointer_id;
  uint8_t sensor_number;
  int available_led;

  assert (sdr_ctx);
  assert (sdr_record);
  assert (sdr_record_len);
  assert (arg);

  sdr_callback_arg = (struct ipmi_oem_ibm_get_led_sdr_callback *)arg;
  state_data = sdr_callback_arg->state_data;

  /* IBM OEM
   *
   * From xCAT (http://xcat.sourceforge.net/)
   *
   * Get Led Request
   *
   * 0x3A - OEM network function (is IPMI_NET_FN_OEM_IBM_LED_RQ)
   * 0xC0 - OEM cmd
   * 0x?? - LED ID (MS Byte)
   * 0x?? - LED ID (LS Byte)
   *
   * Get Led Response
   *
   * 0xC0 - OEM cmd
   * 0x?? - Completion Code
   * 0x?? - ??
   * 0x?? - LED Active vs. Inactive
   *      - non-zero = active
   *      - 0 = inactive
   * 0x?? - ??
   * 0x?? - LED Pointer ID (MS Byte)
   * 0x?? - LED Pointer ID (LS Byte) / Sensor Number
   *      - Pointer ID means indicating problem elsewhere
   * 0x?? - LED Active Type
   *      - 1 - Indicates LED Active to indicate LED Pointer ID Active
   *      - 2 - Indicates LED Active due to Sensor w/ Sensor Number
   *      - 3 - User manually activated LED
   *      - 4 - BIOS or Administrator lit LED
   */

  if (record_type != IPMI_SDR_FORMAT_OEM_RECORD)
    return (0);

  if (ipmi_sdr_parse_record_id_and_type (state_data->sdr_ctx,
					 sdr_record,
					 sdr_record_len,
					 &record_id,
					 NULL) < 0)
    {
      pstdout_fprintf (state_data->pstate,
		       stderr,
		       "ipmi_sdr_parse_record_id_and_type: %s\n",
		       ipmi_sdr_ctx_errormsg (state_data->sdr_ctx));
      return (-1);
    }

  if ((oem_data_buf_len = ipmi_sdr_parse_oem_data (state_data->sdr_ctx,
						   sdr_record,
						   sdr_record_len,
						   oem_data_buf,
						   IPMI_SDR_MAX_RECORD_LENGTH)) < 0)
    {
      pstdout_fprintf (state_data->pstate,
		       stderr,
		       "ipmi_sdr_parse_oem_data: %s\n",
		       ipmi_sdr_ctx_errormsg (state_data->sdr_ctx));
      return (-1);
    }
      
  /* If not enough data, skip it */
  if (oem_data_buf_len < IPMI_SDR_RECORD_OEM_IBM_LED_OEM_DATA_MIN_LENGTH)
    return (0);

  sensor_type = oem_data_buf[IPMI_SDR_RECORD_OEM_IBM_SENSOR_TYPE_OEM_DATA_INDEX];
      
  /* If not LED sensor type, skip it */
  if (sensor_type != IPMI_SDR_RECORD_OEM_IBM_LED_SENSOR_TYPE)
    return (0);

  /* IBM systems use inconsistent endian, guess endian by assuming
   * LED IDs are numerically started at 0
   */
      
  if (oem_data_buf[IPMI_SDR_RECORD_OEM_IBM_LED_ID_LS_OEM_DATA_INDEX] > oem_data_buf[IPMI_SDR_RECORD_OEM_IBM_LED_ID_MS_OEM_DATA_INDEX])
    {
      led_id_ls = oem_data_buf[IPMI_SDR_RECORD_OEM_IBM_LED_ID_LS_OEM_DATA_INDEX];
      led_id_ms = oem_data_buf[IPMI_SDR_RECORD_OEM_IBM_LED_ID_MS_OEM_DATA_INDEX];
    }
  else
    {
      led_id_ls = oem_data_buf[IPMI_SDR_RECORD_OEM_IBM_LED_ID_MS_OEM_DATA_INDEX];
      led_id_ms = oem_data_buf[IPMI_SDR_RECORD_OEM_IBM_LED_ID_LS_OEM_DATA_INDEX];
    }

  led_id = led_id_ls | (led_id_ms << 8);

  bytes_rq[0] = IPMI_CMD_OEM_IBM_GET_LED;
  bytes_rq[1] = led_id_ms;
  bytes_rq[2] = led_id_ls;
      
  if ((rs_len = ipmi_cmd_raw (state_data->ipmi_ctx,
			      0, /* lun */
			      IPMI_NET_FN_OEM_IBM_LED_RQ, /* network function */
			      bytes_rq, /* data */
			      3, /* num bytes */
			      bytes_rs,
			      IPMI_OEM_MAX_BYTES)) < 0)
    {
      pstdout_fprintf (state_data->pstate,
		       stderr,
		       "ipmi_cmd_raw: %s\n",
		       ipmi_ctx_errormsg (state_data->ipmi_ctx));
      return (-1);
    }
      
  /* If get parameter out of range, assume LED ID endian wrong and try again */
  if (rs_len >= 2 && bytes_rs[1] == IPMI_COMP_CODE_PARAMETER_OUT_OF_RANGE)
    {
      bytes_rq[0] = IPMI_CMD_OEM_IBM_GET_LED;
      bytes_rq[1] = led_id_ls;
      bytes_rq[2] = led_id_ms;

      if ((rs_len = ipmi_cmd_raw (state_data->ipmi_ctx,
				  0, /* lun */
				  IPMI_NET_FN_OEM_IBM_LED_RQ, /* network function */
				  bytes_rq, /* data */
				  3, /* num bytes */
				  bytes_rs,
				  IPMI_OEM_MAX_BYTES)) < 0)
	{
	  pstdout_fprintf (state_data->pstate,
			   stderr,
			   "ipmi_cmd_raw: %s\n",
			   ipmi_ctx_errormsg (state_data->ipmi_ctx));
	  return (-1);
	}
    }

  /* achu: there are probably 1 or 2 completion codes that are
   * acceptable to ignore and continue on, but who knows what they
   * are.
   */

  /* Assume this error code means LED not available */
  if (rs_len >= 2 && bytes_rs[1] == IPMI_COMP_CODE_PARAMETER_OUT_OF_RANGE)
    available_led = 0;
  else
    {
      if (ipmi_oem_check_response_and_completion_code (state_data,
						       bytes_rs,
						       rs_len,
						       8,
						       IPMI_CMD_OEM_IBM_GET_LED,
						       IPMI_NET_FN_OEM_IBM_LED_RS,
						       NULL) < 0)
	return (-1);
      
      available_led = 1;
    }

  if (!sdr_callback_arg->header_output_flag)
    {
      memset (fmt, '\0', IPMI_OEM_FMT_BUFLEN + 1);
      
      snprintf (fmt,
		IPMI_OEM_FMT_BUFLEN,
		"%%-%ds | LED               | State    | LED Information\n",
		sdr_callback_arg->column_width->record_id);
      
      pstdout_printf (state_data->pstate,
		      fmt,
		      SENSORS_HEADER_RECORD_ID_STR);
      
      sdr_callback_arg->header_output_flag++;
    }
      
  memset (led_name, '\0', IPMI_OEM_IBM_LED_NAME_BUFLEN + 1);
  memset (led_pointer_name, '\0', IPMI_OEM_IBM_LED_NAME_BUFLEN + 1);
  memset (id_string, '\0', IPMI_OEM_IBM_LED_ID_STRING_BUFLEN + 1);
  memset (led_info, '\0', IPMI_OEM_IBM_LED_INFO_BUFLEN + 1);
      
  if (_get_led_name (state_data,
		     sdr_callback_arg->oem_data,
		     led_id,
		     led_name,
		     IPMI_OEM_IBM_LED_NAME_BUFLEN) < 0)
    return (-1);
      
  if (available_led)
    {
      led_state = bytes_rs[3];
      led_active_type = bytes_rs[7];
      led_pointer_id = (bytes_rs[5] << 8) | bytes_rs[6];
      sensor_number = bytes_rs[6];

      if (led_state == IPMI_OEM_IBM_LED_STATE_INACTIVE)
	led_state_str = "Inactive";
      else
	led_state_str = "Active";
      
      if (led_state != IPMI_OEM_IBM_LED_STATE_INACTIVE)
	{
	  /* Location LED special case */
	  if (!led_id)
	    {
	      snprintf (led_info,
			IPMI_OEM_IBM_LED_INFO_BUFLEN,
			"System Error Condition");
	    }
	  else if (led_active_type == IPMI_OEM_IBM_LED_ACTIVE_BY_LED)
	    {
	      if (_get_led_name (state_data,
				 sdr_callback_arg->oem_data,
				 led_pointer_id,
				 led_pointer_name,
				 IPMI_OEM_IBM_LED_NAME_BUFLEN) < 0)
		return (-1);
	      
	      snprintf (led_info,
			IPMI_OEM_IBM_LED_INFO_BUFLEN,
			"'%s' Active",
			led_pointer_name);
	    }
	  else if (led_active_type == IPMI_OEM_IBM_LED_ACTIVE_BY_SENSOR)
	    {
	      /* achu: sensor numbers may not be unique.  I'm copying
	       * this algorithm from xCAT so I assume it's safe for
	       * IBM machines b/c IBM lays out their SDRs in a fashion
	       * that this search is safe and won't result in an
	       * incorrect output.
	       */
	      if (_find_sensor (state_data,
				sensor_number,
				id_string,
				IPMI_OEM_IBM_LED_ID_STRING_BUFLEN) < 0)
		return (-1);
	      
	      snprintf (led_info,
			IPMI_OEM_IBM_LED_INFO_BUFLEN,
			"Sensor '%s' error",
			id_string);
	    }
	  else if (led_active_type == IPMI_OEM_IBM_LED_ACTIVE_BY_USER)
	    {
	      snprintf (led_info,
			IPMI_OEM_IBM_LED_INFO_BUFLEN,
			"LED Activated by User");
	    }
	  else if (led_active_type == IPMI_OEM_IBM_LED_ACTIVE_BY_BIOS_OR_ADMINISTRATOR)
	    {
	      snprintf (led_info,
			IPMI_OEM_IBM_LED_INFO_BUFLEN,
			"LED Activated by BIOS or Administrator");
	    }
	}
    }
  else
    led_state_str = "N/A";
      
  snprintf (fmt,
	    IPMI_OEM_FMT_BUFLEN,
	    "%%-%du | %%-%ds | %%-%ds | %s\n",
	    sdr_callback_arg->column_width->record_id,
	    IPMI_OEM_IBM_LED_NAME_COLUMN_SIZE,
	    IPMI_OEM_IBM_LED_STATE_COLUMN_SIZE,
	    led_info);
      
  pstdout_printf (state_data->pstate,
		  fmt,
		  record_id,
		  led_name,
		  led_state_str,
		  led_info);

  return (0);
}
Пример #5
0
static int
_sun_get_led_sdr_callback (ipmi_sdr_ctx_t sdr_ctx,
			   uint8_t record_type,
			   const void *sdr_record,
			   unsigned int sdr_record_len,
			   void *arg)
{
  struct ipmi_oem_sun_get_led_sdr_callback *sdr_callback_arg;
  ipmi_oem_state_data_t *state_data;
  uint8_t bytes_rq[IPMI_OEM_MAX_BYTES];
  uint8_t bytes_rs[IPMI_OEM_MAX_BYTES];
  int rs_len;
  uint16_t record_id;
  char fmt[IPMI_OEM_FMT_BUFLEN + 1];
  char device_id_string[IPMI_SDR_MAX_DEVICE_ID_STRING_LENGTH + 1];
  char sensor_name_buf[IPMI_SDR_MAX_SENSOR_NAME_LENGTH + 1];
  char *sensor_name = NULL;
  uint8_t entity_instance_type;
  uint8_t led_mode;
  char *led_mode_str = NULL;

  assert (sdr_ctx);
  assert (sdr_record);
  assert (sdr_record_len);
  assert (arg);

  sdr_callback_arg = (struct ipmi_oem_sun_get_led_sdr_callback *)arg;
  state_data = sdr_callback_arg->state_data;

  /* Sun OEM
   *
   * From Ipmitool (http://ipmitool.sourceforge.net/)
   *
   * Get Led Request
   *
   * 0x2E - OEM network function (is IPMI_NET_FN_OEM_GROUP_RQ)
   * 0x21 - OEM cmd
   * 0x?? - Device Slave Address (in General Device Locator Record)
   *      - Note that the IPMI command requires the entire
   *        byte of the slave address.
   * 0x?? - LED Type (see below [1])
   *      - 0 - ok2rm
   *      - 1 - service
   *      - 2 - activity
   *      - 3 - locate 
   * 0x?? - Controller Address / Device Access Address (in General Device Locator Record)
   *      - 0x20 if the LED is local
   *      - Note that the IPMI command requires the entire
   *        byte of the access address.
   * 0x?? - HW Info (OEM field in General Device Locator Record)
   * 0x?? - Force
   *      - 0 - Go thru controller
   *      - 1 - Directly access device
   *
   * An alternate format is described in the ipmitool comments for Sun
   * Blade Moduler Systems.
   *
   * 0x2E - OEM network function (is IPMI_NET_FN_OEM_GROUP_RQ)
   * 0x21 - OEM cmd
   * 0x?? - Device Slave Address (in General Device Locator Record)
   * 0x?? - LED Type
   * 0x?? - Controller Address / Device Access Address (in General Device Locator Record)
   * 0x?? - HW Info (OEM field in General Device Locator Record)
   * 0x?? - Entity ID
   * 0x?? - Entity Instance
   *      - 7 bit version
   * 0x?? - Force
   *      - 0 - Go thru controller
   *      - 1 - Directly access device
   *
   * Get Led Response
   *
   * 0x21 - OEM cmd
   * 0x?? - Completion Code
   * 0x?? - LED mode
   *
   * achu notes: 
   *
   * [1] - As far as I can tell, the LED type field is useless.  My
   * assumption is that on older Sun systems, or other motherboards I
   * don't have access to, one can specify an LED type, which allows
   * you to enable/disable a particular LED amongst many.  On my Sun
   * Fire 4140, it appears to do nothing and affect nothing.  I will
   * add in a new option later if it becomes necessary for the user to
   * specify an LED type.  In the meantime, I will copy the code use
   * in ipmitool and set this field to the OEM field.
   */

  if (record_type != IPMI_SDR_FORMAT_GENERIC_DEVICE_LOCATOR_RECORD)
    return (0);

  if (ipmi_sdr_parse_entity_id_instance_type (state_data->sdr_ctx,
					      sdr_record,
					      sdr_record_len,
					      NULL,
					      NULL,
					      &entity_instance_type) < 0)
    {
      pstdout_fprintf (state_data->pstate,
		       stderr,
		       "ipmi_sdr_parse_entity_id_and_instance: %s\n",
		       ipmi_sdr_ctx_errormsg (state_data->sdr_ctx));
      return (-1);
    }
      
  /* if it isn't a physical instance, don't continue on */

  if (entity_instance_type == IPMI_SDR_LOGICAL_CONTAINER_ENTITY)
    return (0);
          
  if (ipmi_sdr_parse_record_id_and_type (state_data->sdr_ctx,
					 sdr_record,
					 sdr_record_len,
					 &record_id,
					 NULL) < 0)
    {
      pstdout_fprintf (state_data->pstate,
		       stderr,
		       "ipmi_sdr_parse_record_id_and_type: %s\n",
		       ipmi_sdr_ctx_errormsg (state_data->sdr_ctx));
      return (-1);
    }

  /* achu: the sun oem commands want the full byte, not just the
   * sub-field, so use indexes instead of sdr-parse lib.
   */

  bytes_rq[0] = IPMI_CMD_OEM_SUN_GET_LED;
  bytes_rq[1] = ((uint8_t *)sdr_record)[IPMI_SDR_RECORD_GENERIC_DEVICE_LOCATOR_DEVICE_SLAVE_ADDRESS_INDEX];
  bytes_rq[2] = ((uint8_t *)sdr_record)[IPMI_SDR_RECORD_GENERIC_DEVICE_LOCATOR_OEM_INDEX];
  bytes_rq[3] = ((uint8_t *)sdr_record)[IPMI_SDR_RECORD_GENERIC_DEVICE_LOCATOR_DEVICE_ACCESS_ADDRESS_INDEX];
  bytes_rq[4] = ((uint8_t *)sdr_record)[IPMI_SDR_RECORD_GENERIC_DEVICE_LOCATOR_OEM_INDEX];
  bytes_rq[5] = IPMI_OEM_SUN_LED_FORCE_GO_THRU_CONTROLLER;

  if ((rs_len = ipmi_cmd_raw (state_data->ipmi_ctx,
			      0, /* lun */
			      IPMI_NET_FN_OEM_GROUP_RQ, /* network function */
			      bytes_rq, /* data */
			      6, /* num bytes */
			      bytes_rs,
			      IPMI_OEM_MAX_BYTES)) < 0)
    {
      pstdout_fprintf (state_data->pstate,
		       stderr,
		       "ipmi_cmd_raw: %s\n",
		       ipmi_ctx_errormsg (state_data->ipmi_ctx));
      return (-1);
    }
  
  /* achu: there are probably 1 or 2 completion codes that are
   * acceptable to ignore and continue on, but who knows what they
   * are.
   */

  if (ipmi_oem_check_response_and_completion_code (state_data,
						   bytes_rs,
						   rs_len,
						   3,
						   IPMI_CMD_OEM_SUN_GET_LED,
						   IPMI_NET_FN_OEM_GROUP_RS,
						   NULL) < 0)
    return (-1);
  
  if (!sdr_callback_arg->header_output_flag)
    {
      memset (fmt, '\0', IPMI_OEM_FMT_BUFLEN + 1);
      
      snprintf (fmt,
		IPMI_OEM_FMT_BUFLEN,
		"%%-%ds | %%-%ds | LED Mode\n",
		sdr_callback_arg->column_width->record_id,
		sdr_callback_arg->column_width->sensor_name);
      
      pstdout_printf (state_data->pstate,
		      fmt,
		      SENSORS_HEADER_RECORD_ID_STR,
		      SENSORS_HEADER_NAME_STR);
          
      sdr_callback_arg->header_output_flag++;
    }
      
  led_mode = bytes_rs[2];
      
  if (state_data->prog_data->args->verbose_count)
    {
      memset (sensor_name_buf, '\0', IPMI_SDR_MAX_SENSOR_NAME_LENGTH + 1);
      
      if (ipmi_sdr_parse_entity_sensor_name (state_data->sdr_ctx,
					     NULL,
					     0,
					     0, /* sensor number */
					     IPMI_SDR_SENSOR_NAME_FLAGS_IGNORE_SHARED_SENSORS, /* flags */
					     sensor_name_buf,
					     IPMI_SDR_MAX_SENSOR_NAME_LENGTH) < 0)
	{
	  pstdout_fprintf (state_data->pstate,
			   stderr,
			   "ipmi_sdr_parse_entity_sensor_name: %s\n",
			   ipmi_sdr_ctx_errormsg (state_data->sdr_ctx));
	  return (-1);
	}
          
      sensor_name = sensor_name_buf;
    }
  else
    {
      memset (device_id_string, '\0', IPMI_SDR_MAX_DEVICE_ID_STRING_LENGTH + 1);
      
      if (ipmi_sdr_parse_device_id_string (state_data->sdr_ctx,
					   sdr_record,
					   sdr_record_len,
					   device_id_string,
					   IPMI_SDR_MAX_DEVICE_ID_STRING_LENGTH) < 0)
	{
	  pstdout_fprintf (state_data->pstate,
			   stderr,
			   "ipmi_sdr_parse_device_id_string: %s\n",
			   ipmi_sdr_ctx_errormsg (state_data->sdr_ctx));
	  return (-1);
	}
      
      sensor_name = device_id_string;
    }
      
  switch (led_mode)
    {
    case IPMI_OEM_SUN_LED_MODE_OFF:
      led_mode_str = "Off";
      break;
    case IPMI_OEM_SUN_LED_MODE_ON:
      led_mode_str = "On";
      break;
    case IPMI_OEM_SUN_LED_MODE_STANDBY:
      led_mode_str = "Standby";
      break;
    case IPMI_OEM_SUN_LED_MODE_SLOW:
      led_mode_str = "Slow";
      break;
    case IPMI_OEM_SUN_LED_MODE_FAST:
      led_mode_str = "Fast";
      break;
    default:
      led_mode_str = "Unknown";
    }
  
  snprintf (fmt,
	    IPMI_OEM_FMT_BUFLEN,
	    "%%-%du | %%-%ds | %s\n",
	    sdr_callback_arg->column_width->record_id,
	    sdr_callback_arg->column_width->sensor_name,
	    led_mode_str);
      
  pstdout_printf (state_data->pstate,
		  fmt,
		  record_id,
		  sensor_name);

  return (0);
}
Пример #6
0
int
ipmi_oem_sun_set_led (ipmi_oem_state_data_t *state_data)
{
  uint8_t bytes_rq[IPMI_OEM_MAX_BYTES];
  uint8_t bytes_rs[IPMI_OEM_MAX_BYTES];
  int rs_len;
  uint16_t record_id;
  uint8_t led_mode;
  long value;
  char *ptr;
  uint8_t sdr_record[IPMI_SDR_MAX_RECORD_LENGTH];
  int sdr_record_len = 0;
  uint8_t record_type;
  uint8_t entity_instance_type;
  int rv = -1;

  assert (state_data);
  assert (state_data->prog_data->args->oem_options_count == 2);

  errno = 0;
  value = strtol (state_data->prog_data->args->oem_options[0], &ptr, 10);
  if (errno
      || ptr[0] != '\0'
      || value < 0
      || value < IPMI_SDR_RECORD_ID_FIRST
      || value > IPMI_SDR_RECORD_ID_LAST)
    {
      pstdout_fprintf (state_data->pstate,
                       stderr,
                       "%s:%s invalid record_id\n",
                       state_data->prog_data->args->oem_id,
                       state_data->prog_data->args->oem_command);
      goto cleanup;
    }

  record_id = value;

  if (strcasecmp (state_data->prog_data->args->oem_options[1], "off")
      && strcasecmp (state_data->prog_data->args->oem_options[1], "on")
      && strcasecmp (state_data->prog_data->args->oem_options[1], "standby")
      && strcasecmp (state_data->prog_data->args->oem_options[1], "slow")
      && strcasecmp (state_data->prog_data->args->oem_options[1], "fast"))
    {
      pstdout_fprintf (state_data->pstate,
                       stderr,
                       "%s:%s invalid OEM option argument '%s'\n",
                       state_data->prog_data->args->oem_id,
                       state_data->prog_data->args->oem_command,
                       state_data->prog_data->args->oem_options[1]);
      goto cleanup;
    }

  if (!strcasecmp (state_data->prog_data->args->oem_options[1], "off"))
    led_mode = IPMI_OEM_SUN_LED_MODE_OFF;
  else if (!strcasecmp (state_data->prog_data->args->oem_options[1], "on"))
    led_mode = IPMI_OEM_SUN_LED_MODE_ON;
  else if (!strcasecmp (state_data->prog_data->args->oem_options[1], "standby"))
    led_mode = IPMI_OEM_SUN_LED_MODE_STANDBY;
  else if (!strcasecmp (state_data->prog_data->args->oem_options[1], "slow"))
    led_mode = IPMI_OEM_SUN_LED_MODE_SLOW;
  else /* !strcasecmp (state_data->prog_data->args->oem_options[1], "fast") */
    led_mode = IPMI_OEM_SUN_LED_MODE_FAST;

  if (sdr_cache_create_and_load (state_data->sdr_ctx,
                                 state_data->pstate,
                                 state_data->ipmi_ctx,
                                 state_data->hostname,
 				 &state_data->prog_data->args->common_args) < 0)
    goto cleanup;

  /* Sun OEM
   *
   * From Ipmitool (http://ipmitool.sourceforge.net/)
   *
   * Set Led Request
   *
   * 0x2E - OEM network function (is IPMI_NET_FN_OEM_GROUP_RQ)
   * 0x22 - OEM cmd
   * 0x?? - Device Slave Address (in General Device Locator Record)
   *      - Note that the IPMI command requires the entire
   *        byte of the slave address.
   * 0x?? - LED Type (see below [1])
   *      - 0 - ok2rm
   *      - 1 - service
   *      - 2 - activity
   *      - 3 - locate 
   * 0x?? - Controller Address / Device Access Address (in General Device Locator Record)
   *      - 0x20 if the LED is local
   *      - Note that the IPMI command requires the entire
   *        byte of the access address.
   * 0x?? - HW Info (OEM field in General Device Locator Record)
   * 0x?? - LED Mode
   * 0x?? - Force
   *      - 0 - Go thru controller
   *      - 1 - Directly access device
   * 0x?? - Role
   *      - Ipmitool comments state "Used by BMC for authorization purposes"
   *      - achu: I have no idea what this is for, set to 0 like in code
   *
   * An alternate format is described in the ipmitool comments for Sun
   * Blade Moduler Systems.
   *
   * 0x2E - OEM network function (is IPMI_NET_FN_OEM_GROUP_RQ)
   * 0x22 - OEM cmd
   * 0x?? - Device Slave Address (in General Device Locator Record)
   * 0x?? - LED Type
   * 0x?? - Controller Address / Device Access Address (in General Device Locator Record)
   * 0x?? - HW Info (OEM field in General Device Locator Record)
   * 0x?? - LED Mode
   * 0x?? - Entity ID
   * 0x?? - Entity Instance
   *      - 7 bit version
   * 0x?? - Force
   *      - 0 - Go thru controller
   *      - 1 - Directly access device
   * 0x?? - Role
   *      - Ipmitool comments state "Used by BMC for authorization purposes"
   *      - achu: I have no idea what this is for, set to 0 like in code
   *
   * Set Led Response
   *
   * 0x22 - OEM cmd
   * 0x?? - Completion Code
   *
   * achu notes: 
   *
   * [1] - As far as I can tell, the LED type field is useless.  My
   * assumption is that on older Sun systems, or other motherboards I
   * don't have access to, one can specify an LED type, which allows
   * you to enable/disable a particular LED amongst many.  On my Sun
   * Fire 4140, it appears to do nothing and affect nothing.  I will
   * add in a new option later if it becomes necessary for the user to
   * specify an LED type.  In the meantime, I will copy the code use
   * in ipmitool and set this field to the OEM field.
   */
  
  if (ipmi_sdr_cache_search_record_id (state_data->sdr_ctx, record_id) < 0)
    {
      pstdout_fprintf (state_data->pstate,
                       stderr,
                       "ipmi_sdr_cache_search_record_id: %s\n",
                       ipmi_sdr_ctx_errormsg (state_data->sdr_ctx));
      goto cleanup;
    }
  
  if ((sdr_record_len = ipmi_sdr_cache_record_read (state_data->sdr_ctx,
                                                    sdr_record,
                                                    IPMI_SDR_MAX_RECORD_LENGTH)) < 0)
    {
      pstdout_fprintf (state_data->pstate,
                       stderr,
                       "ipmi_sdr_cache_record_read: %s\n",
                       ipmi_sdr_ctx_errormsg (state_data->sdr_ctx));
      goto cleanup;
    }
  
  if (ipmi_sdr_parse_record_id_and_type (state_data->sdr_ctx,
                                         sdr_record,
                                         sdr_record_len,
                                         NULL,
                                         &record_type) < 0)
    {
      pstdout_fprintf (state_data->pstate,
                       stderr,
                       "ipmi_sdr_parse_record_id_and_type: %s\n",
                       ipmi_sdr_ctx_errormsg (state_data->sdr_ctx));
      goto cleanup;
    }
  
  if (record_type != IPMI_SDR_FORMAT_GENERIC_DEVICE_LOCATOR_RECORD)
    {
      pstdout_fprintf (state_data->pstate,
                       stderr,
                       "Record ID points to invalid record type: %Xh\n",
                       record_type);
      goto cleanup;
    }
  
  if (ipmi_sdr_parse_entity_id_instance_type (state_data->sdr_ctx,
                                              sdr_record,
                                              sdr_record_len,
                                              NULL,
                                              NULL,
                                              &entity_instance_type) < 0)
    {
      pstdout_fprintf (state_data->pstate,
                       stderr,
                       "ipmi_sdr_parse_entity_id_and_instance: %s\n",
                       ipmi_sdr_ctx_errormsg (state_data->sdr_ctx));
      goto cleanup;
    }

  if (entity_instance_type != IPMI_SDR_PHYSICAL_ENTITY)
    {
      pstdout_fprintf (state_data->pstate,
                       stderr,
                       "Record ID points to non physical entity\n");
      goto cleanup;
    }
  
  /* achu: the sun oem commands want the full byte, not just the
   * sub-field, so use indexes instead of sdr-parse lib.
   */
  
  bytes_rq[0] = IPMI_CMD_OEM_SUN_SET_LED;
  bytes_rq[1] = sdr_record[IPMI_SDR_RECORD_GENERIC_DEVICE_LOCATOR_DEVICE_SLAVE_ADDRESS_INDEX];
  bytes_rq[2] = sdr_record[IPMI_SDR_RECORD_GENERIC_DEVICE_LOCATOR_OEM_INDEX];
  bytes_rq[3] = sdr_record[IPMI_SDR_RECORD_GENERIC_DEVICE_LOCATOR_DEVICE_ACCESS_ADDRESS_INDEX];
  bytes_rq[4] = sdr_record[IPMI_SDR_RECORD_GENERIC_DEVICE_LOCATOR_OEM_INDEX];
  bytes_rq[5] = led_mode;
  bytes_rq[6] = IPMI_OEM_SUN_LED_FORCE_GO_THRU_CONTROLLER;
  bytes_rq[7] = 0;              /* see comments above, just set to 0 */
  
  if ((rs_len = ipmi_cmd_raw (state_data->ipmi_ctx,
                              0, /* lun */
                              IPMI_NET_FN_OEM_GROUP_RQ, /* network function */
                              bytes_rq, /* data */
                              8, /* num bytes */
                              bytes_rs,
                              IPMI_OEM_MAX_BYTES)) < 0)
    {
      pstdout_fprintf (state_data->pstate,
                       stderr,
                       "ipmi_cmd_raw: %s\n",
                       ipmi_ctx_errormsg (state_data->ipmi_ctx));
      goto cleanup;
    }
      
  if (ipmi_oem_check_response_and_completion_code (state_data,
                                                   bytes_rs,
                                                   rs_len,
                                                   2,
                                                   IPMI_CMD_OEM_SUN_SET_LED,
                                                   IPMI_NET_FN_OEM_GROUP_RS,
                                                   NULL) < 0)
    goto cleanup;
 
  rv = 0;
 cleanup: 
  return (rv);
}
Пример #7
0
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);
}
int
ipmi_sensors_simple_output (ipmi_sensors_state_data_t *state_data,
                            uint8_t sensor_number,
                            double *sensor_reading,
                            int event_message_output_type,
                            uint16_t sensor_event_bitmask,
                            char **event_message_list,
                            unsigned int event_message_list_len)
{
  uint16_t record_id;
  uint8_t record_type;

  assert (state_data);
  assert (IPMI_SENSORS_EVENT_VALID (event_message_output_type));

  if (ipmi_sdr_parse_record_id_and_type (state_data->sdr_ctx,
                                         NULL,
                                         0,
                                         &record_id,
                                         &record_type) < 0)
    {
      pstdout_fprintf (state_data->pstate,
                       stderr,
                       "ipmi_sdr_parse_record_id_and_type: %s\n",
                       ipmi_sdr_ctx_errormsg (state_data->sdr_ctx));
      return (-1);
    }

  if (!state_data->output_headers)
    {
      _output_headers (state_data);
      state_data->output_headers++;
    }

  switch (record_type)
    {
    case IPMI_SDR_FORMAT_FULL_SENSOR_RECORD:
      if (state_data->prog_data->args->legacy_output)
        return (_legacy_simple_output_full_record (state_data,
                                                   record_id,
                                                   sensor_reading,
                                                   event_message_output_type,
                                                   sensor_event_bitmask,
                                                   event_message_list,
                                                   event_message_list_len));
      else if (state_data->prog_data->args->ipmimonitoring_legacy_output)
        return (_ipmimonitoring_legacy_simple_output_full_record (state_data,
                                                                  record_id,
                                                                  sensor_reading,
                                                                  event_message_output_type,
                                                                  sensor_event_bitmask,
                                                                  event_message_list,
                                                                  event_message_list_len));
      else
        return (_simple_output_full_record (state_data,
                                            record_id,
                                            sensor_number,
                                            sensor_reading,
                                            event_message_output_type,
                                            sensor_event_bitmask,
                                            event_message_list,
                                            event_message_list_len));
    case IPMI_SDR_FORMAT_COMPACT_SENSOR_RECORD:
      if (state_data->prog_data->args->legacy_output)
        return (_legacy_simple_output_compact_record (state_data,
                                                      record_id,
                                                      event_message_output_type,
                                                      sensor_event_bitmask,
                                                      event_message_list,
                                                      event_message_list_len));
      else if (state_data->prog_data->args->ipmimonitoring_legacy_output)
        return (_ipmimonitoring_legacy_simple_output_compact_record (state_data,
                                                                     record_id,
                                                                     event_message_output_type,
                                                                     sensor_event_bitmask,
                                                                     event_message_list,
                                                                     event_message_list_len));
      else
        return (_simple_output_compact_record (state_data,
                                               record_id,
                                               sensor_number,
                                               event_message_output_type,
                                               sensor_event_bitmask,
                                               event_message_list,
                                               event_message_list_len));
    default:
      /* don't output any other types in simple mode */
      break;
    }

  return (0);
}