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 * 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 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 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 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 * 3812eeaed14Srobj ipmi_sdr_hash_convert(const void *p) 3822eeaed14Srobj { 3832eeaed14Srobj return (p); 3842eeaed14Srobj } 3852eeaed14Srobj 3862eeaed14Srobj static ulong_t 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 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 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 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 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 * 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 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 * 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 * 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 * 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 * 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 * 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 * 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 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