19113a79cSeschrock /*
29113a79cSeschrock * CDDL HEADER START
39113a79cSeschrock *
49113a79cSeschrock * The contents of this file are subject to the terms of the
59113a79cSeschrock * Common Development and Distribution License (the "License").
69113a79cSeschrock * You may not use this file except in compliance with the License.
79113a79cSeschrock *
89113a79cSeschrock * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
99113a79cSeschrock * or http://www.opensolaris.org/os/licensing.
109113a79cSeschrock * See the License for the specific language governing permissions
119113a79cSeschrock * and limitations under the License.
129113a79cSeschrock *
139113a79cSeschrock * When distributing Covered Code, include this CDDL HEADER in each
149113a79cSeschrock * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
159113a79cSeschrock * If applicable, add the following below this CDDL HEADER, with the
169113a79cSeschrock * fields enclosed by brackets "[]" replaced with your own identifying
179113a79cSeschrock * information: Portions Copyright [yyyy] [name of copyright owner]
189113a79cSeschrock *
199113a79cSeschrock * CDDL HEADER END
209113a79cSeschrock */
219113a79cSeschrock
229113a79cSeschrock /*
23*81d9f076SRobert Johnston * Copyright 2010 Sun Microsystems, Inc. All rights reserved.
249113a79cSeschrock * Use is subject to license terms.
259113a79cSeschrock */
269113a79cSeschrock
279113a79cSeschrock #include <libipmi.h>
289113a79cSeschrock #include <stddef.h>
299113a79cSeschrock #include <string.h>
302eeaed14Srobj #include <strings.h>
31825ba0f2Srobj #include <math.h>
329113a79cSeschrock
339113a79cSeschrock #include "ipmi_impl.h"
349113a79cSeschrock
35825ba0f2Srobj /*
36825ba0f2Srobj * This macros are used by ipmi_sdr_conv_reading. They were taken verbatim from
37825ba0f2Srobj * the source for ipmitool (v1.88)
38825ba0f2Srobj */
39825ba0f2Srobj #define tos32(val, bits) ((val & ((1<<((bits)-1)))) ? (-((val) & \
40825ba0f2Srobj (1<<((bits)-1))) | (val)) : (val))
41825ba0f2Srobj
42825ba0f2Srobj #define __TO_TOL(mtol) (uint16_t)(BSWAP_16(mtol) & 0x3f)
43825ba0f2Srobj
44825ba0f2Srobj #define __TO_M(mtol) (int16_t)(tos32((((BSWAP_16(mtol) & 0xff00) >> 8) | \
45825ba0f2Srobj ((BSWAP_16(mtol) & 0xc0) << 2)), 10))
46825ba0f2Srobj
47825ba0f2Srobj #define __TO_B(bacc) (int32_t)(tos32((((BSWAP_32(bacc) & \
48825ba0f2Srobj 0xff000000) >> 24) | \
49825ba0f2Srobj ((BSWAP_32(bacc) & 0xc00000) >> 14)), 10))
50825ba0f2Srobj
51825ba0f2Srobj #define __TO_ACC(bacc) (uint32_t)(((BSWAP_32(bacc) & 0x3f0000) >> 16) | \
52825ba0f2Srobj ((BSWAP_32(bacc) & 0xf000) >> 6))
53825ba0f2Srobj
54825ba0f2Srobj #define __TO_ACC_EXP(bacc) (uint32_t)((BSWAP_32(bacc) & 0xc00) >> 10)
55825ba0f2Srobj #define __TO_R_EXP(bacc) (int32_t)(tos32(((BSWAP_32(bacc) & 0xf0) >> 4),\
56825ba0f2Srobj 4))
57825ba0f2Srobj #define __TO_B_EXP(bacc) (int32_t)(tos32((BSWAP_32(bacc) & 0xf), 4))
58825ba0f2Srobj
59825ba0f2Srobj #define SDR_SENSOR_L_LINEAR 0x00
60825ba0f2Srobj #define SDR_SENSOR_L_LN 0x01
61825ba0f2Srobj #define SDR_SENSOR_L_LOG10 0x02
62825ba0f2Srobj #define SDR_SENSOR_L_LOG2 0x03
63825ba0f2Srobj #define SDR_SENSOR_L_E 0x04
64825ba0f2Srobj #define SDR_SENSOR_L_EXP10 0x05
65825ba0f2Srobj #define SDR_SENSOR_L_EXP2 0x06
66825ba0f2Srobj #define SDR_SENSOR_L_1_X 0x07
67825ba0f2Srobj #define SDR_SENSOR_L_SQR 0x08
68825ba0f2Srobj #define SDR_SENSOR_L_CUBE 0x09
69825ba0f2Srobj #define SDR_SENSOR_L_SQRT 0x0a
70825ba0f2Srobj #define SDR_SENSOR_L_CUBERT 0x0b
71825ba0f2Srobj #define SDR_SENSOR_L_NONLINEAR 0x70
72825ba0f2Srobj
73825ba0f2Srobj /*
74825ba0f2Srobj * Analog sensor reading data formats
75825ba0f2Srobj *
76825ba0f2Srobj * See Section 43.1
77825ba0f2Srobj */
78825ba0f2Srobj #define IPMI_DATA_FMT_UNSIGNED 0
79825ba0f2Srobj #define IPMI_DATA_FMT_ONESCOMP 1
80825ba0f2Srobj #define IPMI_DATA_FMT_TWOSCOMP 2
81825ba0f2Srobj
82e5dcf7beSRobert Johnston #define IPMI_SDR_HDR_SZ offsetof(ipmi_sdr_t, is_record)
83e5dcf7beSRobert Johnston
842eeaed14Srobj typedef struct ipmi_sdr_cache_ent {
852eeaed14Srobj char *isc_name;
862eeaed14Srobj struct ipmi_sdr *isc_sdr;
872eeaed14Srobj ipmi_hash_link_t isc_link;
882eeaed14Srobj } ipmi_sdr_cache_ent_t;
892eeaed14Srobj
909113a79cSeschrock typedef struct ipmi_cmd_get_sdr {
919113a79cSeschrock uint16_t ic_gs_resid;
929113a79cSeschrock uint16_t ic_gs_recid;
939113a79cSeschrock uint8_t ic_gs_offset;
949113a79cSeschrock uint8_t ic_gs_len;
959113a79cSeschrock } ipmi_cmd_get_sdr_t;
969113a79cSeschrock
979113a79cSeschrock typedef struct ipmi_rsp_get_sdr {
989113a79cSeschrock uint16_t ir_gs_next;
999113a79cSeschrock uint8_t ir_gs_record[1];
1009113a79cSeschrock } ipmi_rsp_get_sdr_t;
1019113a79cSeschrock
1029113a79cSeschrock /*
1032eeaed14Srobj * "Get SDR Repostiory Info" command.
1042eeaed14Srobj */
1052eeaed14Srobj ipmi_sdr_info_t *
ipmi_sdr_get_info(ipmi_handle_t * ihp)1062eeaed14Srobj ipmi_sdr_get_info(ipmi_handle_t *ihp)
1072eeaed14Srobj {
1082eeaed14Srobj ipmi_cmd_t cmd, *rsp;
1092eeaed14Srobj ipmi_sdr_info_t *sip;
110e1a24155Srobj uint16_t tmp16;
111e1a24155Srobj uint32_t tmp32;
1122eeaed14Srobj
1132eeaed14Srobj cmd.ic_netfn = IPMI_NETFN_STORAGE;
1142eeaed14Srobj cmd.ic_lun = 0;
1152eeaed14Srobj cmd.ic_cmd = IPMI_CMD_GET_SDR_INFO;
1162eeaed14Srobj cmd.ic_dlen = 0;
1172eeaed14Srobj cmd.ic_data = NULL;
1182eeaed14Srobj
1192eeaed14Srobj if ((rsp = ipmi_send(ihp, &cmd)) == NULL)
1202eeaed14Srobj return (NULL);
1212eeaed14Srobj
1222eeaed14Srobj sip = rsp->ic_data;
1232eeaed14Srobj
124e1a24155Srobj tmp16 = LE_IN16(&sip->isi_record_count);
125e1a24155Srobj (void) memcpy(&sip->isi_record_count, &tmp16, sizeof (tmp16));
126e1a24155Srobj
127e1a24155Srobj tmp16 = LE_IN16(&sip->isi_free_space);
128e1a24155Srobj (void) memcpy(&sip->isi_free_space, &tmp16, sizeof (tmp16));
129e1a24155Srobj
130e1a24155Srobj tmp32 = LE_IN32(&sip->isi_add_ts);
131e1a24155Srobj (void) memcpy(&sip->isi_add_ts, &tmp32, sizeof (tmp32));
132e1a24155Srobj
133e1a24155Srobj tmp32 = LE_IN32(&sip->isi_erase_ts);
134e1a24155Srobj (void) memcpy(&sip->isi_erase_ts, &tmp32, sizeof (tmp32));
1352eeaed14Srobj
1362eeaed14Srobj return (sip);
1372eeaed14Srobj }
1382eeaed14Srobj
1392eeaed14Srobj /*
1409113a79cSeschrock * Issue the "Reserve SDR Repository" command.
1419113a79cSeschrock */
1429113a79cSeschrock static int
ipmi_sdr_reserve_repository(ipmi_handle_t * ihp)1439113a79cSeschrock ipmi_sdr_reserve_repository(ipmi_handle_t *ihp)
1449113a79cSeschrock {
1459113a79cSeschrock ipmi_cmd_t cmd, *rsp;
1469113a79cSeschrock
1479113a79cSeschrock cmd.ic_netfn = IPMI_NETFN_STORAGE;
1489113a79cSeschrock cmd.ic_lun = 0;
1499113a79cSeschrock cmd.ic_cmd = IPMI_CMD_RESERVE_SDR_REPOSITORY;
1509113a79cSeschrock cmd.ic_dlen = 0;
1519113a79cSeschrock cmd.ic_data = NULL;
1529113a79cSeschrock
1539113a79cSeschrock if ((rsp = ipmi_send(ihp, &cmd)) == NULL)
1549113a79cSeschrock return (-1);
1559113a79cSeschrock
1569113a79cSeschrock ihp->ih_reservation = *((uint16_t *)rsp->ic_data);
1579113a79cSeschrock return (0);
1589113a79cSeschrock }
1599113a79cSeschrock
1609113a79cSeschrock /*
1612eeaed14Srobj * Returns B_TRUE if the repository has changed since the cached copy was last
1622eeaed14Srobj * referenced.
1632eeaed14Srobj */
1642eeaed14Srobj boolean_t
ipmi_sdr_changed(ipmi_handle_t * ihp)1652eeaed14Srobj ipmi_sdr_changed(ipmi_handle_t *ihp)
1662eeaed14Srobj {
1672eeaed14Srobj ipmi_sdr_info_t *sip;
1682eeaed14Srobj
1692eeaed14Srobj if ((sip = ipmi_sdr_get_info(ihp)) == NULL)
1702eeaed14Srobj return (B_TRUE);
1712eeaed14Srobj
1722eeaed14Srobj return (sip->isi_add_ts > ihp->ih_sdr_ts ||
1732eeaed14Srobj sip->isi_erase_ts > ihp->ih_sdr_ts ||
1742eeaed14Srobj ipmi_hash_first(ihp->ih_sdr_cache) == NULL);
1752eeaed14Srobj }
1762eeaed14Srobj
1772eeaed14Srobj /*
1789113a79cSeschrock * Refresh the cache of sensor data records.
1799113a79cSeschrock */
1802eeaed14Srobj int
ipmi_sdr_refresh(ipmi_handle_t * ihp)1819113a79cSeschrock ipmi_sdr_refresh(ipmi_handle_t *ihp)
1829113a79cSeschrock {
1839113a79cSeschrock uint16_t id;
1849113a79cSeschrock ipmi_sdr_t *sdr;
1859113a79cSeschrock ipmi_sdr_cache_ent_t *ent;
186e5dcf7beSRobert Johnston size_t namelen;
1872eeaed14Srobj uint8_t type;
1882eeaed14Srobj char *name;
1892eeaed14Srobj ipmi_sdr_info_t *sip;
190*81d9f076SRobert Johnston uint32_t isi_add_ts, isi_erase_ts;
1912eeaed14Srobj
1922eeaed14Srobj if ((sip = ipmi_sdr_get_info(ihp)) == NULL)
1932eeaed14Srobj return (-1);
1942eeaed14Srobj
195*81d9f076SRobert Johnston (void) memcpy(&isi_add_ts, &sip->isi_add_ts, sizeof (uint32_t));
196*81d9f076SRobert Johnston (void) memcpy(&isi_erase_ts, &sip->isi_erase_ts, sizeof (uint32_t));
197*81d9f076SRobert Johnston if (isi_add_ts <= ihp->ih_sdr_ts &&
198*81d9f076SRobert Johnston isi_erase_ts <= ihp->ih_sdr_ts &&
1992eeaed14Srobj ipmi_hash_first(ihp->ih_sdr_cache) != NULL)
2002eeaed14Srobj return (0);
2019113a79cSeschrock
20292ba7109Seschrock ipmi_sdr_clear(ihp);
2032eeaed14Srobj ipmi_entity_clear(ihp);
204*81d9f076SRobert Johnston ihp->ih_sdr_ts = MAX(isi_add_ts, isi_erase_ts);
2059113a79cSeschrock
2069113a79cSeschrock /*
2079113a79cSeschrock * Iterate over all existing SDRs and add them to the cache.
2089113a79cSeschrock */
2099113a79cSeschrock id = IPMI_SDR_FIRST;
2109113a79cSeschrock while (id != IPMI_SDR_LAST) {
2119113a79cSeschrock if ((sdr = ipmi_sdr_get(ihp, id, &id)) == NULL)
212283bfb4dSEric Schrock goto error;
2139113a79cSeschrock
2149113a79cSeschrock /*
2152eeaed14Srobj * Extract the name from the record-specific data.
2169113a79cSeschrock */
2179113a79cSeschrock switch (sdr->is_type) {
2189113a79cSeschrock case IPMI_SDR_TYPE_GENERIC_LOCATOR:
2192eeaed14Srobj {
2202eeaed14Srobj ipmi_sdr_generic_locator_t *glp =
2212eeaed14Srobj (ipmi_sdr_generic_locator_t *)
2222eeaed14Srobj sdr->is_record;
2232eeaed14Srobj namelen = glp->is_gl_idlen;
2242eeaed14Srobj type = glp->is_gl_idtype;
2252eeaed14Srobj name = glp->is_gl_idstring;
2269113a79cSeschrock break;
2272eeaed14Srobj }
2289113a79cSeschrock
2299113a79cSeschrock case IPMI_SDR_TYPE_FRU_LOCATOR:
2302eeaed14Srobj {
2312eeaed14Srobj ipmi_sdr_fru_locator_t *flp =
2322eeaed14Srobj (ipmi_sdr_fru_locator_t *)
2332eeaed14Srobj sdr->is_record;
2342eeaed14Srobj namelen = flp->is_fl_idlen;
2352eeaed14Srobj name = flp->is_fl_idstring;
2362eeaed14Srobj type = flp->is_fl_idtype;
2379113a79cSeschrock break;
2389113a79cSeschrock }
2399113a79cSeschrock
2402eeaed14Srobj case IPMI_SDR_TYPE_COMPACT_SENSOR:
2412eeaed14Srobj {
2422eeaed14Srobj ipmi_sdr_compact_sensor_t *csp =
2432eeaed14Srobj (ipmi_sdr_compact_sensor_t *)
2442eeaed14Srobj sdr->is_record;
245e1a24155Srobj uint16_t tmp;
246e1a24155Srobj
2472eeaed14Srobj namelen = csp->is_cs_idlen;
2482eeaed14Srobj type = csp->is_cs_idtype;
2492eeaed14Srobj name = csp->is_cs_idstring;
2502eeaed14Srobj
251e1a24155Srobj tmp = LE_IN16(&csp->is_cs_assert_mask);
252e1a24155Srobj (void) memcpy(&csp->is_cs_assert_mask, &tmp,
253e1a24155Srobj sizeof (tmp));
254e1a24155Srobj
255e1a24155Srobj tmp = LE_IN16(&csp->is_cs_deassert_mask);
256e1a24155Srobj (void) memcpy(&csp->is_cs_deassert_mask, &tmp,
257e1a24155Srobj sizeof (tmp));
258e1a24155Srobj
259e1a24155Srobj tmp = LE_IN16(&csp->is_cs_reading_mask);
260e1a24155Srobj (void) memcpy(&csp->is_cs_reading_mask, &tmp,
261e1a24155Srobj sizeof (tmp));
2622eeaed14Srobj break;
2639113a79cSeschrock }
2649113a79cSeschrock
2652eeaed14Srobj case IPMI_SDR_TYPE_FULL_SENSOR:
2662eeaed14Srobj {
267e1a24155Srobj ipmi_sdr_full_sensor_t *fsp =
2682eeaed14Srobj (ipmi_sdr_full_sensor_t *)
2692eeaed14Srobj sdr->is_record;
270e1a24155Srobj uint16_t tmp;
2712eeaed14Srobj
272e1a24155Srobj namelen = fsp->is_fs_idlen;
273e1a24155Srobj type = fsp->is_fs_idtype;
274e1a24155Srobj name = fsp->is_fs_idstring;
275e1a24155Srobj
276e1a24155Srobj tmp = LE_IN16(&fsp->is_fs_assert_mask);
277e1a24155Srobj (void) memcpy(&fsp->is_fs_assert_mask, &tmp,
278e1a24155Srobj sizeof (tmp));
279e1a24155Srobj
280e1a24155Srobj tmp = LE_IN16(&fsp->is_fs_deassert_mask);
281e1a24155Srobj (void) memcpy(&fsp->is_fs_deassert_mask, &tmp,
282e1a24155Srobj sizeof (tmp));
283e1a24155Srobj
284e1a24155Srobj tmp = LE_IN16(&fsp->is_fs_reading_mask);
285e1a24155Srobj (void) memcpy(&fsp->is_fs_reading_mask, &tmp,
286e1a24155Srobj sizeof (tmp));
2872eeaed14Srobj break;
2889113a79cSeschrock }
2899113a79cSeschrock
2902eeaed14Srobj case IPMI_SDR_TYPE_EVENT_ONLY:
2912eeaed14Srobj {
2922eeaed14Srobj ipmi_sdr_event_only_t *esp =
2932eeaed14Srobj (ipmi_sdr_event_only_t *)
2942eeaed14Srobj sdr->is_record;
2952eeaed14Srobj namelen = esp->is_eo_idlen;
2962eeaed14Srobj type = esp->is_eo_idtype;
2972eeaed14Srobj name = esp->is_eo_idstring;
2982eeaed14Srobj break;
2992eeaed14Srobj }
3002eeaed14Srobj
3012eeaed14Srobj case IPMI_SDR_TYPE_MANAGEMENT_LOCATOR:
3022eeaed14Srobj {
3032eeaed14Srobj ipmi_sdr_management_locator_t *msp =
3042eeaed14Srobj (ipmi_sdr_management_locator_t *)
3052eeaed14Srobj sdr->is_record;
3062eeaed14Srobj namelen = msp->is_ml_idlen;
3072eeaed14Srobj type = msp->is_ml_idtype;
3082eeaed14Srobj name = msp->is_ml_idstring;
3092eeaed14Srobj break;
3102eeaed14Srobj }
3112eeaed14Srobj
3122eeaed14Srobj case IPMI_SDR_TYPE_MANAGEMENT_CONFIRMATION:
3132eeaed14Srobj {
3142eeaed14Srobj ipmi_sdr_management_confirmation_t *mcp =
3152eeaed14Srobj (ipmi_sdr_management_confirmation_t *)
3162eeaed14Srobj sdr->is_record;
317e1a24155Srobj uint16_t tmp;
318e1a24155Srobj
3192eeaed14Srobj name = NULL;
320e1a24155Srobj tmp = LE_IN16(&mcp->is_mc_product);
321e1a24155Srobj (void) memcpy(&mcp->is_mc_product, &tmp,
322e1a24155Srobj sizeof (tmp));
3232eeaed14Srobj break;
3242eeaed14Srobj }
3252eeaed14Srobj
3262eeaed14Srobj default:
3272eeaed14Srobj name = NULL;
3282eeaed14Srobj }
3292eeaed14Srobj
3302eeaed14Srobj if ((ent = ipmi_zalloc(ihp,
331e5dcf7beSRobert Johnston sizeof (ipmi_sdr_cache_ent_t))) == NULL) {
332e5dcf7beSRobert Johnston free(sdr);
333283bfb4dSEric Schrock goto error;
3342eeaed14Srobj }
335e5dcf7beSRobert Johnston
336e5dcf7beSRobert Johnston ent->isc_sdr = sdr;
3372eeaed14Srobj
3382eeaed14Srobj if (name != NULL) {
3392eeaed14Srobj if ((ent->isc_name = ipmi_alloc(ihp, namelen + 1)) ==
3402eeaed14Srobj NULL) {
3412eeaed14Srobj ipmi_free(ihp, ent->isc_sdr);
3422eeaed14Srobj ipmi_free(ihp, ent);
343283bfb4dSEric Schrock goto error;
3442eeaed14Srobj }
3452eeaed14Srobj
3462eeaed14Srobj ipmi_decode_string(type, namelen, name, ent->isc_name);
3472eeaed14Srobj }
3482eeaed14Srobj
3492092e3b9Seschrock /*
3502092e3b9Seschrock * This should never happen. It means that the SP has returned
3512092e3b9Seschrock * a SDR record twice, with the same name and ID. This has
3522092e3b9Seschrock * been observed on service processors that don't correctly
3532092e3b9Seschrock * return SDR_LAST during iteration, so assume we've looped in
3542092e3b9Seschrock * the SDR and return gracefully.
3552092e3b9Seschrock */
3562092e3b9Seschrock if (ipmi_hash_lookup(ihp->ih_sdr_cache, ent) != NULL) {
3572092e3b9Seschrock ipmi_free(ihp, ent->isc_sdr);
3582092e3b9Seschrock ipmi_free(ihp, ent->isc_name);
3592092e3b9Seschrock ipmi_free(ihp, ent);
3602092e3b9Seschrock break;
3612092e3b9Seschrock }
3622092e3b9Seschrock
3632eeaed14Srobj ipmi_hash_insert(ihp->ih_sdr_cache, ent);
3642eeaed14Srobj }
3652eeaed14Srobj
3662eeaed14Srobj return (0);
367283bfb4dSEric Schrock
368283bfb4dSEric Schrock error:
369283bfb4dSEric Schrock ipmi_sdr_clear(ihp);
370283bfb4dSEric Schrock ipmi_entity_clear(ihp);
371283bfb4dSEric Schrock return (-1);
3722eeaed14Srobj }
3732eeaed14Srobj
3742eeaed14Srobj /*
3752eeaed14Srobj * Hash routines. We allow lookup by name, but since not all entries have
3762eeaed14Srobj * names, we fall back to the entry pointer, which is guaranteed to be unique.
3772eeaed14Srobj * The end result is that entities without names cannot be looked up, but will
3782eeaed14Srobj * show up during iteration.
3792eeaed14Srobj */
3802eeaed14Srobj static const void *
ipmi_sdr_hash_convert(const void * p)3812eeaed14Srobj ipmi_sdr_hash_convert(const void *p)
3822eeaed14Srobj {
3832eeaed14Srobj return (p);
3842eeaed14Srobj }
3852eeaed14Srobj
3862eeaed14Srobj static ulong_t
ipmi_sdr_hash_compute(const void * p)3872eeaed14Srobj ipmi_sdr_hash_compute(const void *p)
3882eeaed14Srobj {
3892eeaed14Srobj const ipmi_sdr_cache_ent_t *ep = p;
3902eeaed14Srobj
3912eeaed14Srobj if (ep->isc_name)
3922eeaed14Srobj return (ipmi_hash_strhash(ep->isc_name));
3932eeaed14Srobj else
3942eeaed14Srobj return (ipmi_hash_ptrhash(ep));
3952eeaed14Srobj }
3962eeaed14Srobj
3972eeaed14Srobj static int
ipmi_sdr_hash_compare(const void * a,const void * b)3982eeaed14Srobj ipmi_sdr_hash_compare(const void *a, const void *b)
3992eeaed14Srobj {
4002eeaed14Srobj const ipmi_sdr_cache_ent_t *ap = a;
4012eeaed14Srobj const ipmi_sdr_cache_ent_t *bp = b;
4022eeaed14Srobj
4032eeaed14Srobj if (ap->isc_name == NULL || bp->isc_name == NULL)
4042eeaed14Srobj return (-1);
4052eeaed14Srobj
4062092e3b9Seschrock if (strcmp(ap->isc_name, bp->isc_name) != 0)
4072092e3b9Seschrock return (-1);
4082092e3b9Seschrock
4092092e3b9Seschrock /*
4102092e3b9Seschrock * While it is strange for a service processor to report multiple
4112092e3b9Seschrock * entries with the same name, we allow it by treating the (name, id)
4122092e3b9Seschrock * as the unique identifier. When looking up by name, the SDR pointer
4132092e3b9Seschrock * is NULL, and we return the first matching name.
4142092e3b9Seschrock */
4152092e3b9Seschrock if (ap->isc_sdr == NULL || bp->isc_sdr == NULL)
4162092e3b9Seschrock return (0);
4172092e3b9Seschrock
4182092e3b9Seschrock if (ap->isc_sdr->is_id == bp->isc_sdr->is_id)
4192092e3b9Seschrock return (0);
4202092e3b9Seschrock else
4212092e3b9Seschrock return (-1);
4222eeaed14Srobj }
4232eeaed14Srobj
4242eeaed14Srobj int
ipmi_sdr_init(ipmi_handle_t * ihp)4252eeaed14Srobj ipmi_sdr_init(ipmi_handle_t *ihp)
4262eeaed14Srobj {
4272eeaed14Srobj if ((ihp->ih_sdr_cache = ipmi_hash_create(ihp,
4282eeaed14Srobj offsetof(ipmi_sdr_cache_ent_t, isc_link),
4292eeaed14Srobj ipmi_sdr_hash_convert, ipmi_sdr_hash_compute,
4302eeaed14Srobj ipmi_sdr_hash_compare)) == NULL)
4312eeaed14Srobj return (-1);
4322eeaed14Srobj
4339113a79cSeschrock return (0);
4349113a79cSeschrock }
4359113a79cSeschrock
43692ba7109Seschrock void
ipmi_sdr_clear(ipmi_handle_t * ihp)43792ba7109Seschrock ipmi_sdr_clear(ipmi_handle_t *ihp)
43892ba7109Seschrock {
4392eeaed14Srobj ipmi_sdr_cache_ent_t *ent;
44092ba7109Seschrock
4412eeaed14Srobj while ((ent = ipmi_hash_first(ihp->ih_sdr_cache)) != NULL) {
4422eeaed14Srobj ipmi_hash_remove(ihp->ih_sdr_cache, ent);
4432eeaed14Srobj ipmi_free(ihp, ent->isc_sdr);
4442eeaed14Srobj ipmi_free(ihp, ent->isc_name);
44592ba7109Seschrock ipmi_free(ihp, ent);
4462eeaed14Srobj }
4472eeaed14Srobj }
4482eeaed14Srobj
4492eeaed14Srobj void
ipmi_sdr_fini(ipmi_handle_t * ihp)4502eeaed14Srobj ipmi_sdr_fini(ipmi_handle_t *ihp)
4512eeaed14Srobj {
4522eeaed14Srobj if (ihp->ih_sdr_cache != NULL) {
4532eeaed14Srobj ipmi_sdr_clear(ihp);
4542eeaed14Srobj ipmi_hash_destroy(ihp->ih_sdr_cache);
45592ba7109Seschrock }
45692ba7109Seschrock }
45792ba7109Seschrock
4589113a79cSeschrock ipmi_sdr_t *
ipmi_sdr_get(ipmi_handle_t * ihp,uint16_t id,uint16_t * next)4599113a79cSeschrock ipmi_sdr_get(ipmi_handle_t *ihp, uint16_t id, uint16_t *next)
4609113a79cSeschrock {
461e5dcf7beSRobert Johnston uint8_t offset = IPMI_SDR_HDR_SZ, count = 0, chunksz = 16, sdr_sz;
4629113a79cSeschrock ipmi_cmd_t cmd, *rsp;
4639113a79cSeschrock ipmi_cmd_get_sdr_t req;
464e5dcf7beSRobert Johnston ipmi_sdr_t *sdr;
465e5dcf7beSRobert Johnston int i = 0;
466e5dcf7beSRobert Johnston char *buf;
4679113a79cSeschrock
4689113a79cSeschrock req.ic_gs_resid = ihp->ih_reservation;
4699113a79cSeschrock req.ic_gs_recid = id;
4709113a79cSeschrock
4719113a79cSeschrock cmd.ic_netfn = IPMI_NETFN_STORAGE;
4729113a79cSeschrock cmd.ic_lun = 0;
4739113a79cSeschrock cmd.ic_cmd = IPMI_CMD_GET_SDR;
4749113a79cSeschrock cmd.ic_dlen = sizeof (req);
4759113a79cSeschrock cmd.ic_data = &req;
4769113a79cSeschrock
477e5dcf7beSRobert Johnston /*
478e5dcf7beSRobert Johnston * The size of the SDR is contained in the 5th byte of the SDR header,
479e5dcf7beSRobert Johnston * so we'll read the first 5 bytes to get the size, so we know how big
480e5dcf7beSRobert Johnston * to make the buffer.
481e5dcf7beSRobert Johnston */
482e5dcf7beSRobert Johnston req.ic_gs_offset = 0;
483e5dcf7beSRobert Johnston req.ic_gs_len = IPMI_SDR_HDR_SZ;
4849113a79cSeschrock for (i = 0; i < ihp->ih_retries; i++) {
4852eeaed14Srobj if ((rsp = ipmi_send(ihp, &cmd)) != NULL)
4862eeaed14Srobj break;
4872eeaed14Srobj
4889113a79cSeschrock if (ipmi_errno(ihp) != EIPMI_INVALID_RESERVATION)
4899113a79cSeschrock return (NULL);
4909113a79cSeschrock
4919113a79cSeschrock if (ipmi_sdr_reserve_repository(ihp) != 0)
4929113a79cSeschrock return (NULL);
4939113a79cSeschrock req.ic_gs_resid = ihp->ih_reservation;
4949113a79cSeschrock }
4959113a79cSeschrock if (rsp == NULL)
4969113a79cSeschrock return (NULL);
4979113a79cSeschrock
498e5dcf7beSRobert Johnston sdr = (ipmi_sdr_t *)((ipmi_rsp_get_sdr_t *)rsp->ic_data)->ir_gs_record;
499e5dcf7beSRobert Johnston sdr_sz = sdr->is_length;
500e5dcf7beSRobert Johnston
501e5dcf7beSRobert Johnston if ((buf = ipmi_zalloc(ihp, sdr_sz + IPMI_SDR_HDR_SZ)) == NULL) {
502e5dcf7beSRobert Johnston (void) ipmi_set_error(ihp, EIPMI_NOMEM, NULL);
5039113a79cSeschrock return (NULL);
5049113a79cSeschrock }
505e5dcf7beSRobert Johnston (void) memcpy(buf, (void *)sdr, IPMI_SDR_HDR_SZ);
5069113a79cSeschrock
507e5dcf7beSRobert Johnston /*
508e5dcf7beSRobert Johnston * Some SDRs can be bigger than the buffer sizes for a given bmc
509e5dcf7beSRobert Johnston * interface. Therefore we break up the process of reading in an entire
510e5dcf7beSRobert Johnston * SDR into multiple smaller reads.
511e5dcf7beSRobert Johnston */
512a759cb32SRobert Johnston while (count < sdr_sz) {
513e5dcf7beSRobert Johnston req.ic_gs_offset = offset;
514e5dcf7beSRobert Johnston if (chunksz > (sdr_sz - count))
515e5dcf7beSRobert Johnston chunksz = sdr_sz - count;
516e5dcf7beSRobert Johnston req.ic_gs_len = chunksz;
517e5dcf7beSRobert Johnston rsp = ipmi_send(ihp, &cmd);
5189113a79cSeschrock
519e5dcf7beSRobert Johnston if (rsp != NULL) {
520e5dcf7beSRobert Johnston count += chunksz;
521e5dcf7beSRobert Johnston sdr = (ipmi_sdr_t *)
522e5dcf7beSRobert Johnston ((ipmi_rsp_get_sdr_t *)rsp->ic_data)->ir_gs_record;
523e5dcf7beSRobert Johnston (void) memcpy(buf+offset, (void *)sdr, chunksz);
524e5dcf7beSRobert Johnston offset += chunksz;
525e5dcf7beSRobert Johnston i = 0;
526e5dcf7beSRobert Johnston } else if (ipmi_errno(ihp) == EIPMI_INVALID_RESERVATION) {
527a759cb32SRobert Johnston if (i >= ihp->ih_retries ||
528a759cb32SRobert Johnston ipmi_sdr_reserve_repository(ihp) != 0) {
529e5dcf7beSRobert Johnston free(buf);
530e5dcf7beSRobert Johnston return (NULL);
531e5dcf7beSRobert Johnston }
532e5dcf7beSRobert Johnston req.ic_gs_resid = ihp->ih_reservation;
533e5dcf7beSRobert Johnston i++;
534e5dcf7beSRobert Johnston } else {
535e5dcf7beSRobert Johnston free(buf);
536e5dcf7beSRobert Johnston return (NULL);
537e5dcf7beSRobert Johnston }
538e5dcf7beSRobert Johnston }
539e5dcf7beSRobert Johnston *next = ((ipmi_rsp_get_sdr_t *)rsp->ic_data)->ir_gs_next;
540e5dcf7beSRobert Johnston
541e5dcf7beSRobert Johnston return ((ipmi_sdr_t *)buf);
5429113a79cSeschrock }
5439113a79cSeschrock
5442eeaed14Srobj int
ipmi_sdr_iter(ipmi_handle_t * ihp,int (* func)(ipmi_handle_t *,const char *,ipmi_sdr_t *,void *),void * data)5452eeaed14Srobj ipmi_sdr_iter(ipmi_handle_t *ihp, int (*func)(ipmi_handle_t *,
5462eeaed14Srobj const char *, ipmi_sdr_t *, void *), void *data)
5479113a79cSeschrock {
5489113a79cSeschrock ipmi_sdr_cache_ent_t *ent;
5492eeaed14Srobj int ret;
5509113a79cSeschrock
5512eeaed14Srobj if (ipmi_hash_first(ihp->ih_sdr_cache) == NULL &&
5522eeaed14Srobj ipmi_sdr_refresh(ihp) != 0)
5532eeaed14Srobj return (-1);
5542eeaed14Srobj
5552eeaed14Srobj for (ent = ipmi_hash_first(ihp->ih_sdr_cache); ent != NULL;
5562eeaed14Srobj ent = ipmi_hash_next(ihp->ih_sdr_cache, ent)) {
5572eeaed14Srobj if ((ret = func(ihp, ent->isc_name, ent->isc_sdr, data)) != 0)
5582eeaed14Srobj return (ret);
5592eeaed14Srobj }
5602eeaed14Srobj
5612eeaed14Srobj return (0);
5622eeaed14Srobj }
5632eeaed14Srobj
5642eeaed14Srobj ipmi_sdr_t *
ipmi_sdr_lookup(ipmi_handle_t * ihp,const char * idstr)5652eeaed14Srobj ipmi_sdr_lookup(ipmi_handle_t *ihp, const char *idstr)
5662eeaed14Srobj {
5672eeaed14Srobj ipmi_sdr_cache_ent_t *ent, search;
5682eeaed14Srobj
5692eeaed14Srobj if (ipmi_hash_first(ihp->ih_sdr_cache) == NULL &&
5709113a79cSeschrock ipmi_sdr_refresh(ihp) != 0)
5719113a79cSeschrock return (NULL);
5729113a79cSeschrock
5732eeaed14Srobj search.isc_name = (char *)idstr;
5742092e3b9Seschrock search.isc_sdr = NULL;
5752eeaed14Srobj if ((ent = ipmi_hash_lookup(ihp->ih_sdr_cache, &search)) == NULL) {
5769113a79cSeschrock (void) ipmi_set_error(ihp, EIPMI_NOT_PRESENT, NULL);
5779113a79cSeschrock return (NULL);
5789113a79cSeschrock }
5799113a79cSeschrock
5802eeaed14Srobj return (ent->isc_sdr);
5812eeaed14Srobj }
5822eeaed14Srobj
5832eeaed14Srobj static void *
ipmi_sdr_lookup_common(ipmi_handle_t * ihp,const char * idstr,uint8_t type)5842eeaed14Srobj ipmi_sdr_lookup_common(ipmi_handle_t *ihp, const char *idstr,
5852eeaed14Srobj uint8_t type)
5862eeaed14Srobj {
5872eeaed14Srobj ipmi_sdr_t *sdrp;
5882eeaed14Srobj
5892eeaed14Srobj if ((sdrp = ipmi_sdr_lookup(ihp, idstr)) == NULL)
5902eeaed14Srobj return (NULL);
5912eeaed14Srobj
5922eeaed14Srobj if (sdrp->is_type != type) {
5932eeaed14Srobj (void) ipmi_set_error(ihp, EIPMI_NOT_PRESENT, NULL);
5942eeaed14Srobj return (NULL);
5952eeaed14Srobj }
5962eeaed14Srobj
5972eeaed14Srobj return (sdrp->is_record);
5982eeaed14Srobj }
5992eeaed14Srobj
6002eeaed14Srobj ipmi_sdr_fru_locator_t *
ipmi_sdr_lookup_fru(ipmi_handle_t * ihp,const char * idstr)6012eeaed14Srobj ipmi_sdr_lookup_fru(ipmi_handle_t *ihp, const char *idstr)
6022eeaed14Srobj {
6032eeaed14Srobj return (ipmi_sdr_lookup_common(ihp, idstr,
6042eeaed14Srobj IPMI_SDR_TYPE_FRU_LOCATOR));
6052eeaed14Srobj }
6062eeaed14Srobj
6079113a79cSeschrock ipmi_sdr_generic_locator_t *
ipmi_sdr_lookup_generic(ipmi_handle_t * ihp,const char * idstr)6089113a79cSeschrock ipmi_sdr_lookup_generic(ipmi_handle_t *ihp, const char *idstr)
6099113a79cSeschrock {
6102eeaed14Srobj return (ipmi_sdr_lookup_common(ihp, idstr,
6112eeaed14Srobj IPMI_SDR_TYPE_GENERIC_LOCATOR));
6129113a79cSeschrock }
6139113a79cSeschrock
6142eeaed14Srobj ipmi_sdr_compact_sensor_t *
ipmi_sdr_lookup_compact_sensor(ipmi_handle_t * ihp,const char * idstr)6152eeaed14Srobj ipmi_sdr_lookup_compact_sensor(ipmi_handle_t *ihp, const char *idstr)
6162eeaed14Srobj {
6172eeaed14Srobj return (ipmi_sdr_lookup_common(ihp, idstr,
6182eeaed14Srobj IPMI_SDR_TYPE_COMPACT_SENSOR));
6192eeaed14Srobj }
6202eeaed14Srobj
6212eeaed14Srobj ipmi_sdr_full_sensor_t *
ipmi_sdr_lookup_full_sensor(ipmi_handle_t * ihp,const char * idstr)6222eeaed14Srobj ipmi_sdr_lookup_full_sensor(ipmi_handle_t *ihp, const char *idstr)
6232eeaed14Srobj {
6242eeaed14Srobj return (ipmi_sdr_lookup_common(ihp, idstr,
6252eeaed14Srobj IPMI_SDR_TYPE_FULL_SENSOR));
6269113a79cSeschrock }
627825ba0f2Srobj
628825ba0f2Srobj /*
629825ba0f2Srobj * Mostly taken from ipmitool source v1.88
630825ba0f2Srobj *
631825ba0f2Srobj * This function converts the raw sensor reading returned by
632825ba0f2Srobj * ipmi_get_sensor_reading to a unit-based value of type double.
633825ba0f2Srobj */
634825ba0f2Srobj int
ipmi_sdr_conv_reading(ipmi_sdr_full_sensor_t * sensor,uint8_t val,double * result)635825ba0f2Srobj ipmi_sdr_conv_reading(ipmi_sdr_full_sensor_t *sensor, uint8_t val,
636825ba0f2Srobj double *result)
637825ba0f2Srobj {
638825ba0f2Srobj int m, b, k1, k2;
639825ba0f2Srobj
640825ba0f2Srobj m = __TO_M(sensor->is_fs_mtol);
641825ba0f2Srobj b = __TO_B(sensor->is_fs_bacc);
642825ba0f2Srobj k1 = __TO_B_EXP(sensor->is_fs_bacc);
643825ba0f2Srobj k2 = __TO_R_EXP(sensor->is_fs_bacc);
644825ba0f2Srobj
645825ba0f2Srobj switch (sensor->is_fs_analog_fmt) {
646825ba0f2Srobj case IPMI_DATA_FMT_UNSIGNED:
647825ba0f2Srobj *result = (double)(((m * val) +
648825ba0f2Srobj (b * pow(10, k1))) * pow(10, k2));
649825ba0f2Srobj break;
650825ba0f2Srobj case IPMI_DATA_FMT_ONESCOMP:
651825ba0f2Srobj if (val & 0x80)
652825ba0f2Srobj val++;
653825ba0f2Srobj /* FALLTHRU */
654825ba0f2Srobj case IPMI_DATA_FMT_TWOSCOMP:
655825ba0f2Srobj *result = (double)(((m * (int8_t)val) +
656825ba0f2Srobj (b * pow(10, k1))) * pow(10, k2));
657825ba0f2Srobj break;
658825ba0f2Srobj default:
659825ba0f2Srobj /* This sensor does not return a numeric reading */
660825ba0f2Srobj return (-1);
661825ba0f2Srobj }
662825ba0f2Srobj
663825ba0f2Srobj switch (sensor->is_fs_sensor_linear_type) {
664825ba0f2Srobj case SDR_SENSOR_L_LN:
665825ba0f2Srobj *result = log(*result);
666825ba0f2Srobj break;
667825ba0f2Srobj case SDR_SENSOR_L_LOG10:
668825ba0f2Srobj *result = log10(*result);
669825ba0f2Srobj break;
670825ba0f2Srobj case SDR_SENSOR_L_LOG2:
671825ba0f2Srobj *result = (double)(log(*result) / log(2.0));
672825ba0f2Srobj break;
673825ba0f2Srobj case SDR_SENSOR_L_E:
674825ba0f2Srobj *result = exp(*result);
675825ba0f2Srobj break;
676825ba0f2Srobj case SDR_SENSOR_L_EXP10:
677825ba0f2Srobj *result = pow(10.0, *result);
678825ba0f2Srobj break;
679825ba0f2Srobj case SDR_SENSOR_L_EXP2:
680825ba0f2Srobj *result = pow(2.0, *result);
681825ba0f2Srobj break;
682825ba0f2Srobj case SDR_SENSOR_L_1_X:
683825ba0f2Srobj *result = pow(*result, -1.0); /* 1/x w/o exception */
684825ba0f2Srobj break;
685825ba0f2Srobj case SDR_SENSOR_L_SQR:
686825ba0f2Srobj *result = pow(*result, 2.0);
687825ba0f2Srobj break;
688825ba0f2Srobj case SDR_SENSOR_L_CUBE:
689825ba0f2Srobj *result = pow(*result, 3.0);
690825ba0f2Srobj break;
691825ba0f2Srobj case SDR_SENSOR_L_SQRT:
692825ba0f2Srobj *result = sqrt(*result);
693825ba0f2Srobj break;
694825ba0f2Srobj case SDR_SENSOR_L_CUBERT:
695825ba0f2Srobj *result = cbrt(*result);
696825ba0f2Srobj break;
697825ba0f2Srobj case SDR_SENSOR_L_LINEAR:
698825ba0f2Srobj default:
699825ba0f2Srobj break;
700825ba0f2Srobj }
701825ba0f2Srobj return (0);
702825ba0f2Srobj }
703