2N/A/*
2N/A * CDDL HEADER START
2N/A *
2N/A * The contents of this file are subject to the terms of the
2N/A * Common Development and Distribution License (the "License").
2N/A * You may not use this file except in compliance with the License.
2N/A *
2N/A * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
2N/A * or http://www.opensolaris.org/os/licensing.
2N/A * See the License for the specific language governing permissions
2N/A * and limitations under the License.
2N/A *
2N/A * When distributing Covered Code, include this CDDL HEADER in each
2N/A * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
2N/A * If applicable, add the following below this CDDL HEADER, with the
2N/A * fields enclosed by brackets "[]" replaced with your own identifying
2N/A * information: Portions Copyright [yyyy] [name of copyright owner]
2N/A *
2N/A * CDDL HEADER END
2N/A */
2N/A
2N/A/*
2N/A * Copyright 2010 Sun Microsystems, Inc. All rights reserved.
2N/A * Use is subject to license terms.
2N/A */
2N/A
2N/A#include <libipmi.h>
2N/A#include <stddef.h>
2N/A#include <string.h>
2N/A#include <strings.h>
2N/A#include <math.h>
2N/A
2N/A#include "ipmi_impl.h"
2N/A
2N/A/*
2N/A * This macros are used by ipmi_sdr_conv_reading. They were taken verbatim from
2N/A * the source for ipmitool (v1.88)
2N/A */
2N/A#define tos32(val, bits) ((val & ((1<<((bits)-1)))) ? (-((val) & \
2N/A (1<<((bits)-1))) | (val)) : (val))
2N/A
2N/A#define __TO_TOL(mtol) (uint16_t)(BSWAP_16(mtol) & 0x3f)
2N/A
2N/A#define __TO_M(mtol) (int16_t)(tos32((((BSWAP_16(mtol) & 0xff00) >> 8) | \
2N/A ((BSWAP_16(mtol) & 0xc0) << 2)), 10))
2N/A
2N/A#define __TO_B(bacc) (int32_t)(tos32((((BSWAP_32(bacc) & \
2N/A 0xff000000) >> 24) | \
2N/A ((BSWAP_32(bacc) & 0xc00000) >> 14)), 10))
2N/A
2N/A#define __TO_ACC(bacc) (uint32_t)(((BSWAP_32(bacc) & 0x3f0000) >> 16) | \
2N/A ((BSWAP_32(bacc) & 0xf000) >> 6))
2N/A
2N/A#define __TO_ACC_EXP(bacc) (uint32_t)((BSWAP_32(bacc) & 0xc00) >> 10)
2N/A#define __TO_R_EXP(bacc) (int32_t)(tos32(((BSWAP_32(bacc) & 0xf0) >> 4),\
2N/A 4))
2N/A#define __TO_B_EXP(bacc) (int32_t)(tos32((BSWAP_32(bacc) & 0xf), 4))
2N/A
2N/A#define SDR_SENSOR_L_LINEAR 0x00
2N/A#define SDR_SENSOR_L_LN 0x01
2N/A#define SDR_SENSOR_L_LOG10 0x02
2N/A#define SDR_SENSOR_L_LOG2 0x03
2N/A#define SDR_SENSOR_L_E 0x04
2N/A#define SDR_SENSOR_L_EXP10 0x05
2N/A#define SDR_SENSOR_L_EXP2 0x06
2N/A#define SDR_SENSOR_L_1_X 0x07
2N/A#define SDR_SENSOR_L_SQR 0x08
2N/A#define SDR_SENSOR_L_CUBE 0x09
2N/A#define SDR_SENSOR_L_SQRT 0x0a
2N/A#define SDR_SENSOR_L_CUBERT 0x0b
2N/A#define SDR_SENSOR_L_NONLINEAR 0x70
2N/A
2N/A/*
2N/A * Analog sensor reading data formats
2N/A *
2N/A * See Section 43.1
2N/A */
2N/A#define IPMI_DATA_FMT_UNSIGNED 0
2N/A#define IPMI_DATA_FMT_ONESCOMP 1
2N/A#define IPMI_DATA_FMT_TWOSCOMP 2
2N/A
2N/A#define IPMI_SDR_HDR_SZ offsetof(ipmi_sdr_t, is_record)
2N/A
2N/Atypedef struct ipmi_sdr_cache_ent {
2N/A char *isc_name;
2N/A struct ipmi_sdr *isc_sdr;
2N/A ipmi_hash_link_t isc_link;
2N/A} ipmi_sdr_cache_ent_t;
2N/A
2N/Atypedef struct ipmi_cmd_get_sdr {
2N/A uint16_t ic_gs_resid;
2N/A uint16_t ic_gs_recid;
2N/A uint8_t ic_gs_offset;
2N/A uint8_t ic_gs_len;
2N/A} ipmi_cmd_get_sdr_t;
2N/A
2N/Atypedef struct ipmi_rsp_get_sdr {
2N/A uint16_t ir_gs_next;
2N/A uint8_t ir_gs_record[1];
2N/A} ipmi_rsp_get_sdr_t;
2N/A
2N/A/*
2N/A * "Get SDR Repostiory Info" command.
2N/A */
2N/Aipmi_sdr_info_t *
2N/Aipmi_sdr_get_info(ipmi_handle_t *ihp)
2N/A{
2N/A ipmi_cmd_t cmd, *rsp;
2N/A ipmi_sdr_info_t *sip;
2N/A uint16_t tmp16;
2N/A uint32_t tmp32;
2N/A
2N/A cmd.ic_netfn = IPMI_NETFN_STORAGE;
2N/A cmd.ic_lun = 0;
2N/A cmd.ic_cmd = IPMI_CMD_GET_SDR_INFO;
2N/A cmd.ic_dlen = 0;
2N/A cmd.ic_data = NULL;
2N/A
2N/A if ((rsp = ipmi_send(ihp, &cmd)) == NULL)
2N/A return (NULL);
2N/A
2N/A sip = rsp->ic_data;
2N/A
2N/A tmp16 = LE_IN16(&sip->isi_record_count);
2N/A (void) memcpy(&sip->isi_record_count, &tmp16, sizeof (tmp16));
2N/A
2N/A tmp16 = LE_IN16(&sip->isi_free_space);
2N/A (void) memcpy(&sip->isi_free_space, &tmp16, sizeof (tmp16));
2N/A
2N/A tmp32 = LE_IN32(&sip->isi_add_ts);
2N/A (void) memcpy(&sip->isi_add_ts, &tmp32, sizeof (tmp32));
2N/A
2N/A tmp32 = LE_IN32(&sip->isi_erase_ts);
2N/A (void) memcpy(&sip->isi_erase_ts, &tmp32, sizeof (tmp32));
2N/A
2N/A return (sip);
2N/A}
2N/A
2N/A/*
2N/A * Issue the "Reserve SDR Repository" command.
2N/A */
2N/Astatic int
2N/Aipmi_sdr_reserve_repository(ipmi_handle_t *ihp)
2N/A{
2N/A ipmi_cmd_t cmd, *rsp;
2N/A
2N/A cmd.ic_netfn = IPMI_NETFN_STORAGE;
2N/A cmd.ic_lun = 0;
2N/A cmd.ic_cmd = IPMI_CMD_RESERVE_SDR_REPOSITORY;
2N/A cmd.ic_dlen = 0;
2N/A cmd.ic_data = NULL;
2N/A
2N/A if ((rsp = ipmi_send(ihp, &cmd)) == NULL)
2N/A return (-1);
2N/A
2N/A ihp->ih_reservation = *((uint16_t *)rsp->ic_data);
2N/A return (0);
2N/A}
2N/A
2N/A/*
2N/A * Returns B_TRUE if the repository has changed since the cached copy was last
2N/A * referenced.
2N/A */
2N/Aboolean_t
2N/Aipmi_sdr_changed(ipmi_handle_t *ihp)
2N/A{
2N/A ipmi_sdr_info_t *sip;
2N/A
2N/A if ((sip = ipmi_sdr_get_info(ihp)) == NULL)
2N/A return (B_TRUE);
2N/A
2N/A return (sip->isi_add_ts > ihp->ih_sdr_ts ||
2N/A sip->isi_erase_ts > ihp->ih_sdr_ts ||
2N/A ipmi_hash_first(ihp->ih_sdr_cache) == NULL);
2N/A}
2N/A
2N/A/*
2N/A * Refresh the cache of sensor data records.
2N/A */
2N/Aint
2N/Aipmi_sdr_refresh(ipmi_handle_t *ihp)
2N/A{
2N/A uint16_t id;
2N/A ipmi_sdr_t *sdr;
2N/A ipmi_sdr_cache_ent_t *ent;
2N/A size_t namelen;
2N/A uint8_t type;
2N/A char *name;
2N/A ipmi_sdr_info_t *sip;
2N/A uint32_t isi_add_ts, isi_erase_ts;
2N/A
2N/A if ((sip = ipmi_sdr_get_info(ihp)) == NULL)
2N/A return (-1);
2N/A
2N/A (void) memcpy(&isi_add_ts, &sip->isi_add_ts, sizeof (uint32_t));
2N/A (void) memcpy(&isi_erase_ts, &sip->isi_erase_ts, sizeof (uint32_t));
2N/A if (isi_add_ts <= ihp->ih_sdr_ts &&
2N/A isi_erase_ts <= ihp->ih_sdr_ts &&
2N/A ipmi_hash_first(ihp->ih_sdr_cache) != NULL)
2N/A return (0);
2N/A
2N/A ipmi_sdr_clear(ihp);
2N/A ipmi_entity_clear(ihp);
2N/A ihp->ih_sdr_ts = MAX(isi_add_ts, isi_erase_ts);
2N/A
2N/A /*
2N/A * Iterate over all existing SDRs and add them to the cache.
2N/A */
2N/A id = IPMI_SDR_FIRST;
2N/A while (id != IPMI_SDR_LAST) {
2N/A if ((sdr = ipmi_sdr_get(ihp, id, &id)) == NULL)
2N/A goto error;
2N/A
2N/A /*
2N/A * Extract the name from the record-specific data.
2N/A */
2N/A switch (sdr->is_type) {
2N/A case IPMI_SDR_TYPE_GENERIC_LOCATOR:
2N/A {
2N/A ipmi_sdr_generic_locator_t *glp =
2N/A (ipmi_sdr_generic_locator_t *)
2N/A sdr->is_record;
2N/A namelen = glp->is_gl_idlen;
2N/A type = glp->is_gl_idtype;
2N/A name = glp->is_gl_idstring;
2N/A break;
2N/A }
2N/A
2N/A case IPMI_SDR_TYPE_FRU_LOCATOR:
2N/A {
2N/A ipmi_sdr_fru_locator_t *flp =
2N/A (ipmi_sdr_fru_locator_t *)
2N/A sdr->is_record;
2N/A namelen = flp->is_fl_idlen;
2N/A name = flp->is_fl_idstring;
2N/A type = flp->is_fl_idtype;
2N/A break;
2N/A }
2N/A
2N/A case IPMI_SDR_TYPE_COMPACT_SENSOR:
2N/A {
2N/A ipmi_sdr_compact_sensor_t *csp =
2N/A (ipmi_sdr_compact_sensor_t *)
2N/A sdr->is_record;
2N/A uint16_t tmp;
2N/A
2N/A namelen = csp->is_cs_idlen;
2N/A type = csp->is_cs_idtype;
2N/A name = csp->is_cs_idstring;
2N/A
2N/A tmp = LE_IN16(&csp->is_cs_assert_mask);
2N/A (void) memcpy(&csp->is_cs_assert_mask, &tmp,
2N/A sizeof (tmp));
2N/A
2N/A tmp = LE_IN16(&csp->is_cs_deassert_mask);
2N/A (void) memcpy(&csp->is_cs_deassert_mask, &tmp,
2N/A sizeof (tmp));
2N/A
2N/A tmp = LE_IN16(&csp->is_cs_reading_mask);
2N/A (void) memcpy(&csp->is_cs_reading_mask, &tmp,
2N/A sizeof (tmp));
2N/A break;
2N/A }
2N/A
2N/A case IPMI_SDR_TYPE_FULL_SENSOR:
2N/A {
2N/A ipmi_sdr_full_sensor_t *fsp =
2N/A (ipmi_sdr_full_sensor_t *)
2N/A sdr->is_record;
2N/A uint16_t tmp;
2N/A
2N/A namelen = fsp->is_fs_idlen;
2N/A type = fsp->is_fs_idtype;
2N/A name = fsp->is_fs_idstring;
2N/A
2N/A tmp = LE_IN16(&fsp->is_fs_assert_mask);
2N/A (void) memcpy(&fsp->is_fs_assert_mask, &tmp,
2N/A sizeof (tmp));
2N/A
2N/A tmp = LE_IN16(&fsp->is_fs_deassert_mask);
2N/A (void) memcpy(&fsp->is_fs_deassert_mask, &tmp,
2N/A sizeof (tmp));
2N/A
2N/A tmp = LE_IN16(&fsp->is_fs_reading_mask);
2N/A (void) memcpy(&fsp->is_fs_reading_mask, &tmp,
2N/A sizeof (tmp));
2N/A break;
2N/A }
2N/A
2N/A case IPMI_SDR_TYPE_EVENT_ONLY:
2N/A {
2N/A ipmi_sdr_event_only_t *esp =
2N/A (ipmi_sdr_event_only_t *)
2N/A sdr->is_record;
2N/A namelen = esp->is_eo_idlen;
2N/A type = esp->is_eo_idtype;
2N/A name = esp->is_eo_idstring;
2N/A break;
2N/A }
2N/A
2N/A case IPMI_SDR_TYPE_MANAGEMENT_LOCATOR:
2N/A {
2N/A ipmi_sdr_management_locator_t *msp =
2N/A (ipmi_sdr_management_locator_t *)
2N/A sdr->is_record;
2N/A namelen = msp->is_ml_idlen;
2N/A type = msp->is_ml_idtype;
2N/A name = msp->is_ml_idstring;
2N/A break;
2N/A }
2N/A
2N/A case IPMI_SDR_TYPE_MANAGEMENT_CONFIRMATION:
2N/A {
2N/A ipmi_sdr_management_confirmation_t *mcp =
2N/A (ipmi_sdr_management_confirmation_t *)
2N/A sdr->is_record;
2N/A uint16_t tmp;
2N/A
2N/A name = NULL;
2N/A tmp = LE_IN16(&mcp->is_mc_product);
2N/A (void) memcpy(&mcp->is_mc_product, &tmp,
2N/A sizeof (tmp));
2N/A break;
2N/A }
2N/A
2N/A default:
2N/A name = NULL;
2N/A }
2N/A
2N/A if ((ent = ipmi_zalloc(ihp,
2N/A sizeof (ipmi_sdr_cache_ent_t))) == NULL) {
2N/A free(sdr);
2N/A goto error;
2N/A }
2N/A
2N/A ent->isc_sdr = sdr;
2N/A
2N/A if (name != NULL) {
2N/A if ((ent->isc_name = ipmi_alloc(ihp, namelen + 1)) ==
2N/A NULL) {
2N/A ipmi_free(ihp, ent->isc_sdr);
2N/A ipmi_free(ihp, ent);
2N/A goto error;
2N/A }
2N/A
2N/A ipmi_decode_string(type, namelen, name, ent->isc_name);
2N/A }
2N/A
2N/A /*
2N/A * This should never happen. It means that the SP has returned
2N/A * a SDR record twice, with the same name and ID. This has
2N/A * been observed on service processors that don't correctly
2N/A * return SDR_LAST during iteration, so assume we've looped in
2N/A * the SDR and return gracefully.
2N/A */
2N/A if (ipmi_hash_lookup(ihp->ih_sdr_cache, ent) != NULL) {
2N/A ipmi_free(ihp, ent->isc_sdr);
2N/A ipmi_free(ihp, ent->isc_name);
2N/A ipmi_free(ihp, ent);
2N/A break;
2N/A }
2N/A
2N/A ipmi_hash_insert(ihp->ih_sdr_cache, ent);
2N/A }
2N/A
2N/A return (0);
2N/A
2N/Aerror:
2N/A ipmi_sdr_clear(ihp);
2N/A ipmi_entity_clear(ihp);
2N/A return (-1);
2N/A}
2N/A
2N/A/*
2N/A * Hash routines. We allow lookup by name, but since not all entries have
2N/A * names, we fall back to the entry pointer, which is guaranteed to be unique.
2N/A * The end result is that entities without names cannot be looked up, but will
2N/A * show up during iteration.
2N/A */
2N/Astatic const void *
2N/Aipmi_sdr_hash_convert(const void *p)
2N/A{
2N/A return (p);
2N/A}
2N/A
2N/Astatic ulong_t
2N/Aipmi_sdr_hash_compute(const void *p)
2N/A{
2N/A const ipmi_sdr_cache_ent_t *ep = p;
2N/A
2N/A if (ep->isc_name)
2N/A return (ipmi_hash_strhash(ep->isc_name));
2N/A else
2N/A return (ipmi_hash_ptrhash(ep));
2N/A}
2N/A
2N/Astatic int
2N/Aipmi_sdr_hash_compare(const void *a, const void *b)
2N/A{
2N/A const ipmi_sdr_cache_ent_t *ap = a;
2N/A const ipmi_sdr_cache_ent_t *bp = b;
2N/A
2N/A if (ap->isc_name == NULL || bp->isc_name == NULL)
2N/A return (-1);
2N/A
2N/A if (strcmp(ap->isc_name, bp->isc_name) != 0)
2N/A return (-1);
2N/A
2N/A /*
2N/A * While it is strange for a service processor to report multiple
2N/A * entries with the same name, we allow it by treating the (name, id)
2N/A * as the unique identifier. When looking up by name, the SDR pointer
2N/A * is NULL, and we return the first matching name.
2N/A */
2N/A if (ap->isc_sdr == NULL || bp->isc_sdr == NULL)
2N/A return (0);
2N/A
2N/A if (ap->isc_sdr->is_id == bp->isc_sdr->is_id)
2N/A return (0);
2N/A else
2N/A return (-1);
2N/A}
2N/A
2N/Aint
2N/Aipmi_sdr_init(ipmi_handle_t *ihp)
2N/A{
2N/A if ((ihp->ih_sdr_cache = ipmi_hash_create(ihp,
2N/A offsetof(ipmi_sdr_cache_ent_t, isc_link),
2N/A ipmi_sdr_hash_convert, ipmi_sdr_hash_compute,
2N/A ipmi_sdr_hash_compare)) == NULL)
2N/A return (-1);
2N/A
2N/A return (0);
2N/A}
2N/A
2N/Avoid
2N/Aipmi_sdr_clear(ipmi_handle_t *ihp)
2N/A{
2N/A ipmi_sdr_cache_ent_t *ent;
2N/A
2N/A while ((ent = ipmi_hash_first(ihp->ih_sdr_cache)) != NULL) {
2N/A ipmi_hash_remove(ihp->ih_sdr_cache, ent);
2N/A ipmi_free(ihp, ent->isc_sdr);
2N/A ipmi_free(ihp, ent->isc_name);
2N/A ipmi_free(ihp, ent);
2N/A }
2N/A}
2N/A
2N/Avoid
2N/Aipmi_sdr_fini(ipmi_handle_t *ihp)
2N/A{
2N/A if (ihp->ih_sdr_cache != NULL) {
2N/A ipmi_sdr_clear(ihp);
2N/A ipmi_hash_destroy(ihp->ih_sdr_cache);
2N/A }
2N/A}
2N/A
2N/Aipmi_sdr_t *
2N/Aipmi_sdr_get(ipmi_handle_t *ihp, uint16_t id, uint16_t *next)
2N/A{
2N/A uint8_t offset = IPMI_SDR_HDR_SZ, count = 0, chunksz = 16, sdr_sz;
2N/A ipmi_cmd_t cmd, *rsp;
2N/A ipmi_cmd_get_sdr_t req;
2N/A ipmi_sdr_t *sdr;
2N/A int i = 0;
2N/A char *buf;
2N/A
2N/A req.ic_gs_resid = ihp->ih_reservation;
2N/A req.ic_gs_recid = id;
2N/A
2N/A cmd.ic_netfn = IPMI_NETFN_STORAGE;
2N/A cmd.ic_lun = 0;
2N/A cmd.ic_cmd = IPMI_CMD_GET_SDR;
2N/A cmd.ic_dlen = sizeof (req);
2N/A cmd.ic_data = &req;
2N/A
2N/A /*
2N/A * The size of the SDR is contained in the 5th byte of the SDR header,
2N/A * so we'll read the first 5 bytes to get the size, so we know how big
2N/A * to make the buffer.
2N/A */
2N/A req.ic_gs_offset = 0;
2N/A req.ic_gs_len = IPMI_SDR_HDR_SZ;
2N/A for (i = 0; i < ihp->ih_retries; i++) {
2N/A if ((rsp = ipmi_send(ihp, &cmd)) != NULL)
2N/A break;
2N/A
2N/A if (ipmi_errno(ihp) != EIPMI_INVALID_RESERVATION)
2N/A return (NULL);
2N/A
2N/A if (ipmi_sdr_reserve_repository(ihp) != 0)
2N/A return (NULL);
2N/A req.ic_gs_resid = ihp->ih_reservation;
2N/A }
2N/A if (rsp == NULL)
2N/A return (NULL);
2N/A
2N/A sdr = (ipmi_sdr_t *)((ipmi_rsp_get_sdr_t *)rsp->ic_data)->ir_gs_record;
2N/A sdr_sz = sdr->is_length;
2N/A
2N/A if ((buf = ipmi_zalloc(ihp, sdr_sz + IPMI_SDR_HDR_SZ)) == NULL) {
2N/A (void) ipmi_set_error(ihp, EIPMI_NOMEM, NULL);
2N/A return (NULL);
2N/A }
2N/A (void) memcpy(buf, (void *)sdr, IPMI_SDR_HDR_SZ);
2N/A
2N/A /*
2N/A * Some SDRs can be bigger than the buffer sizes for a given bmc
2N/A * interface. Therefore we break up the process of reading in an entire
2N/A * SDR into multiple smaller reads.
2N/A */
2N/A while (count < sdr_sz) {
2N/A req.ic_gs_offset = offset;
2N/A if (chunksz > (sdr_sz - count))
2N/A chunksz = sdr_sz - count;
2N/A req.ic_gs_len = chunksz;
2N/A rsp = ipmi_send(ihp, &cmd);
2N/A
2N/A if (rsp != NULL) {
2N/A count += chunksz;
2N/A sdr = (ipmi_sdr_t *)
2N/A ((ipmi_rsp_get_sdr_t *)rsp->ic_data)->ir_gs_record;
2N/A (void) memcpy(buf+offset, (void *)sdr, chunksz);
2N/A offset += chunksz;
2N/A i = 0;
2N/A } else if (ipmi_errno(ihp) == EIPMI_INVALID_RESERVATION) {
2N/A if (i >= ihp->ih_retries ||
2N/A ipmi_sdr_reserve_repository(ihp) != 0) {
2N/A free(buf);
2N/A return (NULL);
2N/A }
2N/A req.ic_gs_resid = ihp->ih_reservation;
2N/A i++;
2N/A } else {
2N/A free(buf);
2N/A return (NULL);
2N/A }
2N/A }
2N/A *next = ((ipmi_rsp_get_sdr_t *)rsp->ic_data)->ir_gs_next;
2N/A
2N/A return ((ipmi_sdr_t *)buf);
2N/A}
2N/A
2N/Aint
2N/Aipmi_sdr_iter(ipmi_handle_t *ihp, int (*func)(ipmi_handle_t *,
2N/A const char *, ipmi_sdr_t *, void *), void *data)
2N/A{
2N/A ipmi_sdr_cache_ent_t *ent;
2N/A int ret;
2N/A
2N/A if (ipmi_hash_first(ihp->ih_sdr_cache) == NULL &&
2N/A ipmi_sdr_refresh(ihp) != 0)
2N/A return (-1);
2N/A
2N/A for (ent = ipmi_hash_first(ihp->ih_sdr_cache); ent != NULL;
2N/A ent = ipmi_hash_next(ihp->ih_sdr_cache, ent)) {
2N/A if ((ret = func(ihp, ent->isc_name, ent->isc_sdr, data)) != 0)
2N/A return (ret);
2N/A }
2N/A
2N/A return (0);
2N/A}
2N/A
2N/Aipmi_sdr_t *
2N/Aipmi_sdr_lookup(ipmi_handle_t *ihp, const char *idstr)
2N/A{
2N/A ipmi_sdr_cache_ent_t *ent, search;
2N/A
2N/A if (ipmi_hash_first(ihp->ih_sdr_cache) == NULL &&
2N/A ipmi_sdr_refresh(ihp) != 0)
2N/A return (NULL);
2N/A
2N/A search.isc_name = (char *)idstr;
2N/A search.isc_sdr = NULL;
2N/A if ((ent = ipmi_hash_lookup(ihp->ih_sdr_cache, &search)) == NULL) {
2N/A (void) ipmi_set_error(ihp, EIPMI_NOT_PRESENT, NULL);
2N/A return (NULL);
2N/A }
2N/A
2N/A return (ent->isc_sdr);
2N/A}
2N/A
2N/Astatic void *
2N/Aipmi_sdr_lookup_common(ipmi_handle_t *ihp, const char *idstr,
2N/A uint8_t type)
2N/A{
2N/A ipmi_sdr_t *sdrp;
2N/A
2N/A if ((sdrp = ipmi_sdr_lookup(ihp, idstr)) == NULL)
2N/A return (NULL);
2N/A
2N/A if (sdrp->is_type != type) {
2N/A (void) ipmi_set_error(ihp, EIPMI_NOT_PRESENT, NULL);
2N/A return (NULL);
2N/A }
2N/A
2N/A return (sdrp->is_record);
2N/A}
2N/A
2N/Aipmi_sdr_fru_locator_t *
2N/Aipmi_sdr_lookup_fru(ipmi_handle_t *ihp, const char *idstr)
2N/A{
2N/A return (ipmi_sdr_lookup_common(ihp, idstr,
2N/A IPMI_SDR_TYPE_FRU_LOCATOR));
2N/A}
2N/A
2N/Aipmi_sdr_generic_locator_t *
2N/Aipmi_sdr_lookup_generic(ipmi_handle_t *ihp, const char *idstr)
2N/A{
2N/A return (ipmi_sdr_lookup_common(ihp, idstr,
2N/A IPMI_SDR_TYPE_GENERIC_LOCATOR));
2N/A}
2N/A
2N/Aipmi_sdr_compact_sensor_t *
2N/Aipmi_sdr_lookup_compact_sensor(ipmi_handle_t *ihp, const char *idstr)
2N/A{
2N/A return (ipmi_sdr_lookup_common(ihp, idstr,
2N/A IPMI_SDR_TYPE_COMPACT_SENSOR));
2N/A}
2N/A
2N/Aipmi_sdr_full_sensor_t *
2N/Aipmi_sdr_lookup_full_sensor(ipmi_handle_t *ihp, const char *idstr)
2N/A{
2N/A return (ipmi_sdr_lookup_common(ihp, idstr,
2N/A IPMI_SDR_TYPE_FULL_SENSOR));
2N/A}
2N/A
2N/A/*
2N/A * Mostly taken from ipmitool source v1.88
2N/A *
2N/A * This function converts the raw sensor reading returned by
2N/A * ipmi_get_sensor_reading to a unit-based value of type double.
2N/A */
2N/Aint
2N/Aipmi_sdr_conv_reading(ipmi_sdr_full_sensor_t *sensor, uint8_t val,
2N/A double *result)
2N/A{
2N/A int m, b, k1, k2;
2N/A
2N/A m = __TO_M(sensor->is_fs_mtol);
2N/A b = __TO_B(sensor->is_fs_bacc);
2N/A k1 = __TO_B_EXP(sensor->is_fs_bacc);
2N/A k2 = __TO_R_EXP(sensor->is_fs_bacc);
2N/A
2N/A switch (sensor->is_fs_analog_fmt) {
2N/A case IPMI_DATA_FMT_UNSIGNED:
2N/A *result = (double)(((m * val) +
2N/A (b * pow(10, k1))) * pow(10, k2));
2N/A break;
2N/A case IPMI_DATA_FMT_ONESCOMP:
2N/A if (val & 0x80)
2N/A val++;
2N/A /* FALLTHRU */
2N/A case IPMI_DATA_FMT_TWOSCOMP:
2N/A *result = (double)(((m * (int8_t)val) +
2N/A (b * pow(10, k1))) * pow(10, k2));
2N/A break;
2N/A default:
2N/A /* This sensor does not return a numeric reading */
2N/A return (-1);
2N/A }
2N/A
2N/A switch (sensor->is_fs_sensor_linear_type) {
2N/A case SDR_SENSOR_L_LN:
2N/A *result = log(*result);
2N/A break;
2N/A case SDR_SENSOR_L_LOG10:
2N/A *result = log10(*result);
2N/A break;
2N/A case SDR_SENSOR_L_LOG2:
2N/A *result = (double)(log(*result) / log(2.0));
2N/A break;
2N/A case SDR_SENSOR_L_E:
2N/A *result = exp(*result);
2N/A break;
2N/A case SDR_SENSOR_L_EXP10:
2N/A *result = pow(10.0, *result);
2N/A break;
2N/A case SDR_SENSOR_L_EXP2:
2N/A *result = pow(2.0, *result);
2N/A break;
2N/A case SDR_SENSOR_L_1_X:
2N/A *result = pow(*result, -1.0); /* 1/x w/o exception */
2N/A break;
2N/A case SDR_SENSOR_L_SQR:
2N/A *result = pow(*result, 2.0);
2N/A break;
2N/A case SDR_SENSOR_L_CUBE:
2N/A *result = pow(*result, 3.0);
2N/A break;
2N/A case SDR_SENSOR_L_SQRT:
2N/A *result = sqrt(*result);
2N/A break;
2N/A case SDR_SENSOR_L_CUBERT:
2N/A *result = cbrt(*result);
2N/A break;
2N/A case SDR_SENSOR_L_LINEAR:
2N/A default:
2N/A break;
2N/A }
2N/A return (0);
2N/A}