1 /*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
7 *
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 */
21
22 /*
23 * Copyright 2010 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
25 */
26 /*
27 * Copyright (c) 2018, Joyent, Inc.
28 */
29
30
31 #include <libipmi.h>
32 #include <stddef.h>
33 #include <string.h>
34 #include <strings.h>
35 #include <math.h>
36
37 #include "ipmi_impl.h"
38
39 /*
40 * This macros are used by ipmi_sdr_conv_reading. They were taken verbatim from
41 * the source for ipmitool (v1.88)
42 */
43 #define tos32(val, bits) ((val & ((1<<((bits)-1)))) ? (-((val) & \
44 (1<<((bits)-1))) | (val)) : (val))
45
46 #define __TO_TOL(mtol) (uint16_t)(BSWAP_16(mtol) & 0x3f)
47
48 #define __TO_M(mtol) (int16_t)(tos32((((BSWAP_16(mtol) & 0xff00) >> 8) | \
49 ((BSWAP_16(mtol) & 0xc0) << 2)), 10))
50
51 #define __TO_B(bacc) (int32_t)(tos32((((BSWAP_32(bacc) & \
52 0xff000000) >> 24) | \
53 ((BSWAP_32(bacc) & 0xc00000) >> 14)), 10))
54
55 #define __TO_ACC(bacc) (uint32_t)(((BSWAP_32(bacc) & 0x3f0000) >> 16) | \
56 ((BSWAP_32(bacc) & 0xf000) >> 6))
57
58 #define __TO_ACC_EXP(bacc) (uint32_t)((BSWAP_32(bacc) & 0xc00) >> 10)
59 #define __TO_R_EXP(bacc) (int32_t)(tos32(((BSWAP_32(bacc) & 0xf0) >> 4),\
60 4))
61 #define __TO_B_EXP(bacc) (int32_t)(tos32((BSWAP_32(bacc) & 0xf), 4))
62
63 #define SDR_SENSOR_L_LINEAR 0x00
64 #define SDR_SENSOR_L_LN 0x01
65 #define SDR_SENSOR_L_LOG10 0x02
66 #define SDR_SENSOR_L_LOG2 0x03
67 #define SDR_SENSOR_L_E 0x04
68 #define SDR_SENSOR_L_EXP10 0x05
69 #define SDR_SENSOR_L_EXP2 0x06
70 #define SDR_SENSOR_L_1_X 0x07
71 #define SDR_SENSOR_L_SQR 0x08
72 #define SDR_SENSOR_L_CUBE 0x09
73 #define SDR_SENSOR_L_SQRT 0x0a
74 #define SDR_SENSOR_L_CUBERT 0x0b
75 #define SDR_SENSOR_L_NONLINEAR 0x70
76
77 /*
78 * Analog sensor reading data formats
79 *
80 * See Section 43.1
81 */
82 #define IPMI_DATA_FMT_UNSIGNED 0
83 #define IPMI_DATA_FMT_ONESCOMP 1
84 #define IPMI_DATA_FMT_TWOSCOMP 2
85
86 #define IPMI_SDR_HDR_SZ offsetof(ipmi_sdr_t, is_record)
87
88 typedef struct ipmi_sdr_cache_ent {
89 char *isc_name;
90 uint8_t isc_entity_id;
91 uint8_t isc_entity_inst;
92 struct ipmi_sdr *isc_sdr;
93 ipmi_hash_link_t isc_link;
94 } ipmi_sdr_cache_ent_t;
95
96 typedef struct ipmi_cmd_get_sdr {
97 uint16_t ic_gs_resid;
98 uint16_t ic_gs_recid;
99 uint8_t ic_gs_offset;
100 uint8_t ic_gs_len;
101 } ipmi_cmd_get_sdr_t;
102
103 typedef struct ipmi_rsp_get_sdr {
104 uint16_t ir_gs_next;
105 uint8_t ir_gs_record[1];
106 } ipmi_rsp_get_sdr_t;
107
108 /*
109 * "Get SDR Repostiory Info" command.
110 */
111 ipmi_sdr_info_t *
ipmi_sdr_get_info(ipmi_handle_t * ihp)112 ipmi_sdr_get_info(ipmi_handle_t *ihp)
113 {
114 ipmi_cmd_t cmd, *rsp;
115 ipmi_sdr_info_t *sip;
116 uint16_t tmp16;
117 uint32_t tmp32;
118
119 cmd.ic_netfn = IPMI_NETFN_STORAGE;
120 cmd.ic_lun = 0;
121 cmd.ic_cmd = IPMI_CMD_GET_SDR_INFO;
122 cmd.ic_dlen = 0;
123 cmd.ic_data = NULL;
124
125 if ((rsp = ipmi_send(ihp, &cmd)) == NULL)
126 return (NULL);
127
128 sip = rsp->ic_data;
129
130 tmp16 = LE_IN16(&sip->isi_record_count);
131 (void) memcpy(&sip->isi_record_count, &tmp16, sizeof (tmp16));
132
133 tmp16 = LE_IN16(&sip->isi_free_space);
134 (void) memcpy(&sip->isi_free_space, &tmp16, sizeof (tmp16));
135
136 tmp32 = LE_IN32(&sip->isi_add_ts);
137 (void) memcpy(&sip->isi_add_ts, &tmp32, sizeof (tmp32));
138
139 tmp32 = LE_IN32(&sip->isi_erase_ts);
140 (void) memcpy(&sip->isi_erase_ts, &tmp32, sizeof (tmp32));
141
142 return (sip);
143 }
144
145 /*
146 * Issue the "Reserve SDR Repository" command.
147 */
148 static int
ipmi_sdr_reserve_repository(ipmi_handle_t * ihp)149 ipmi_sdr_reserve_repository(ipmi_handle_t *ihp)
150 {
151 ipmi_cmd_t cmd, *rsp;
152
153 cmd.ic_netfn = IPMI_NETFN_STORAGE;
154 cmd.ic_lun = 0;
155 cmd.ic_cmd = IPMI_CMD_RESERVE_SDR_REPOSITORY;
156 cmd.ic_dlen = 0;
157 cmd.ic_data = NULL;
158
159 if ((rsp = ipmi_send(ihp, &cmd)) == NULL)
160 return (-1);
161
162 ihp->ih_reservation = *((uint16_t *)rsp->ic_data);
163 return (0);
164 }
165
166 /*
167 * Returns B_TRUE if the repository has changed since the cached copy was last
168 * referenced.
169 */
170 boolean_t
ipmi_sdr_changed(ipmi_handle_t * ihp)171 ipmi_sdr_changed(ipmi_handle_t *ihp)
172 {
173 ipmi_sdr_info_t *sip;
174
175 if ((sip = ipmi_sdr_get_info(ihp)) == NULL)
176 return (B_TRUE);
177
178 return (sip->isi_add_ts > ihp->ih_sdr_ts ||
179 sip->isi_erase_ts > ihp->ih_sdr_ts ||
180 ipmi_hash_first(ihp->ih_sdr_cache) == NULL);
181 }
182
183 /*
184 * Refresh the cache of sensor data records.
185 */
186 int
ipmi_sdr_refresh(ipmi_handle_t * ihp)187 ipmi_sdr_refresh(ipmi_handle_t *ihp)
188 {
189 uint16_t id;
190 ipmi_sdr_t *sdr;
191 ipmi_sdr_cache_ent_t *ent;
192 size_t namelen;
193 uint8_t type, e_id = 0, e_inst = 0;
194 char *name;
195 ipmi_sdr_info_t *sip;
196 uint32_t isi_add_ts, isi_erase_ts;
197
198 if ((sip = ipmi_sdr_get_info(ihp)) == NULL)
199 return (-1);
200
201 (void) memcpy(&isi_add_ts, &sip->isi_add_ts, sizeof (uint32_t));
202 (void) memcpy(&isi_erase_ts, &sip->isi_erase_ts, sizeof (uint32_t));
203 if (isi_add_ts <= ihp->ih_sdr_ts &&
204 isi_erase_ts <= ihp->ih_sdr_ts &&
205 ipmi_hash_first(ihp->ih_sdr_cache) != NULL)
206 return (0);
207
208 ipmi_sdr_clear(ihp);
209 ipmi_entity_clear(ihp);
210 ihp->ih_sdr_ts = MAX(isi_add_ts, isi_erase_ts);
211
212 /*
213 * Iterate over all existing SDRs and add them to the cache.
214 */
215 id = IPMI_SDR_FIRST;
216 while (id != IPMI_SDR_LAST) {
217 if ((sdr = ipmi_sdr_get(ihp, id, &id)) == NULL)
218 goto error;
219
220 /*
221 * Extract the name from the record-specific data.
222 */
223 switch (sdr->is_type) {
224 case IPMI_SDR_TYPE_GENERIC_LOCATOR:
225 {
226 ipmi_sdr_generic_locator_t *glp =
227 (ipmi_sdr_generic_locator_t *)
228 sdr->is_record;
229 namelen = glp->is_gl_idlen;
230 type = glp->is_gl_idtype;
231 name = glp->is_gl_idstring;
232 e_id = glp->is_gl_entity;
233 e_inst = glp->is_gl_instance;
234 break;
235 }
236
237 case IPMI_SDR_TYPE_FRU_LOCATOR:
238 {
239 ipmi_sdr_fru_locator_t *flp =
240 (ipmi_sdr_fru_locator_t *)
241 sdr->is_record;
242 namelen = flp->is_fl_idlen;
243 name = flp->is_fl_idstring;
244 type = flp->is_fl_idtype;
245 e_id = flp->is_fl_entity;
246 e_inst = flp->is_fl_instance;
247 break;
248 }
249
250 case IPMI_SDR_TYPE_COMPACT_SENSOR:
251 {
252 ipmi_sdr_compact_sensor_t *csp =
253 (ipmi_sdr_compact_sensor_t *)
254 sdr->is_record;
255 uint16_t tmp;
256
257 namelen = csp->is_cs_idlen;
258 type = csp->is_cs_idtype;
259 name = csp->is_cs_idstring;
260 e_id = csp->is_cs_entity_id;
261 e_inst = csp->is_cs_entity_instance;
262
263 tmp = LE_IN16(&csp->is_cs_assert_mask);
264 (void) memcpy(&csp->is_cs_assert_mask, &tmp,
265 sizeof (tmp));
266
267 tmp = LE_IN16(&csp->is_cs_deassert_mask);
268 (void) memcpy(&csp->is_cs_deassert_mask, &tmp,
269 sizeof (tmp));
270
271 tmp = LE_IN16(&csp->is_cs_reading_mask);
272 (void) memcpy(&csp->is_cs_reading_mask, &tmp,
273 sizeof (tmp));
274 break;
275 }
276
277 case IPMI_SDR_TYPE_FULL_SENSOR:
278 {
279 ipmi_sdr_full_sensor_t *fsp =
280 (ipmi_sdr_full_sensor_t *)
281 sdr->is_record;
282 uint16_t tmp;
283
284 namelen = fsp->is_fs_idlen;
285 type = fsp->is_fs_idtype;
286 name = fsp->is_fs_idstring;
287 e_id = fsp->is_fs_entity_id;
288 e_inst = fsp->is_fs_entity_instance;
289
290 tmp = LE_IN16(&fsp->is_fs_assert_mask);
291 (void) memcpy(&fsp->is_fs_assert_mask, &tmp,
292 sizeof (tmp));
293
294 tmp = LE_IN16(&fsp->is_fs_deassert_mask);
295 (void) memcpy(&fsp->is_fs_deassert_mask, &tmp,
296 sizeof (tmp));
297
298 tmp = LE_IN16(&fsp->is_fs_reading_mask);
299 (void) memcpy(&fsp->is_fs_reading_mask, &tmp,
300 sizeof (tmp));
301 break;
302 }
303
304 case IPMI_SDR_TYPE_EVENT_ONLY:
305 {
306 ipmi_sdr_event_only_t *esp =
307 (ipmi_sdr_event_only_t *)
308 sdr->is_record;
309 namelen = esp->is_eo_idlen;
310 type = esp->is_eo_idtype;
311 name = esp->is_eo_idstring;
312 e_id = esp->is_eo_entity_id;
313 e_inst = esp->is_eo_entity_instance;
314 break;
315 }
316
317 case IPMI_SDR_TYPE_MANAGEMENT_LOCATOR:
318 {
319 ipmi_sdr_management_locator_t *msp =
320 (ipmi_sdr_management_locator_t *)
321 sdr->is_record;
322 namelen = msp->is_ml_idlen;
323 type = msp->is_ml_idtype;
324 name = msp->is_ml_idstring;
325 e_id = msp->is_ml_entity_id;
326 e_inst = msp->is_ml_entity_instance;
327 break;
328 }
329
330 case IPMI_SDR_TYPE_MANAGEMENT_CONFIRMATION:
331 {
332 ipmi_sdr_management_confirmation_t *mcp =
333 (ipmi_sdr_management_confirmation_t *)
334 sdr->is_record;
335 uint16_t tmp;
336
337 name = NULL;
338 tmp = LE_IN16(&mcp->is_mc_product);
339 (void) memcpy(&mcp->is_mc_product, &tmp,
340 sizeof (tmp));
341 break;
342 }
343
344 default:
345 name = NULL;
346 }
347
348 if ((ent = ipmi_zalloc(ihp,
349 sizeof (ipmi_sdr_cache_ent_t))) == NULL) {
350 free(sdr);
351 goto error;
352 }
353
354 ent->isc_sdr = sdr;
355 ent->isc_entity_id = e_id;
356 ent->isc_entity_inst = e_inst;
357
358 if (name != NULL) {
359 if ((ent->isc_name = ipmi_alloc(ihp, namelen + 1)) ==
360 NULL) {
361 ipmi_free(ihp, ent->isc_sdr);
362 ipmi_free(ihp, ent);
363 goto error;
364 }
365
366 ipmi_decode_string(type, namelen, name, ent->isc_name);
367 }
368
369 /*
370 * This should never happen. It means that the SP has returned
371 * a SDR record twice, with the same name and ID. This has
372 * been observed on service processors that don't correctly
373 * return SDR_LAST during iteration, so assume we've looped in
374 * the SDR and return gracefully.
375 */
376 if (ipmi_hash_lookup(ihp->ih_sdr_cache, ent) != NULL) {
377 ipmi_free(ihp, ent->isc_sdr);
378 ipmi_free(ihp, ent->isc_name);
379 ipmi_free(ihp, ent);
380 break;
381 }
382
383 ipmi_hash_insert(ihp->ih_sdr_cache, ent);
384 }
385
386 return (0);
387
388 error:
389 ipmi_sdr_clear(ihp);
390 ipmi_entity_clear(ihp);
391 return (-1);
392 }
393
394 /*
395 * Hash routines. We allow lookup by name, but since not all entries have
396 * names, we fall back to the entry pointer, which is guaranteed to be unique.
397 * The end result is that entities without names cannot be looked up, but will
398 * show up during iteration.
399 */
400 static const void *
ipmi_sdr_hash_convert(const void * p)401 ipmi_sdr_hash_convert(const void *p)
402 {
403 return (p);
404 }
405
406 static ulong_t
ipmi_sdr_hash_compute(const void * p)407 ipmi_sdr_hash_compute(const void *p)
408 {
409 const ipmi_sdr_cache_ent_t *ep = p;
410
411 if (ep->isc_name)
412 return (ipmi_hash_strhash(ep->isc_name));
413 else
414 return (ipmi_hash_ptrhash(ep));
415 }
416
417 static int
ipmi_sdr_hash_compare(const void * a,const void * b)418 ipmi_sdr_hash_compare(const void *a, const void *b)
419 {
420 const ipmi_sdr_cache_ent_t *ap = a;
421 const ipmi_sdr_cache_ent_t *bp = b;
422
423 if (ap->isc_name == NULL || bp->isc_name == NULL)
424 return (-1);
425
426 if (strcmp(ap->isc_name, bp->isc_name) != 0)
427 return (-1);
428
429 /*
430 * When looking up only by name we return the first matching name. For
431 * a more precise match, callers can optionally specify an IPMI entity
432 * ID and instance that must also match.
433 */
434 if (ap->isc_entity_id != IPMI_ET_UNSPECIFIED &&
435 bp->isc_entity_id != IPMI_ET_UNSPECIFIED) {
436 if (ap->isc_entity_id != bp->isc_entity_id ||
437 ap->isc_entity_inst != bp->isc_entity_inst)
438 return (-1);
439 }
440 return (0);
441 }
442
443 int
ipmi_sdr_init(ipmi_handle_t * ihp)444 ipmi_sdr_init(ipmi_handle_t *ihp)
445 {
446 if ((ihp->ih_sdr_cache = ipmi_hash_create(ihp,
447 offsetof(ipmi_sdr_cache_ent_t, isc_link),
448 ipmi_sdr_hash_convert, ipmi_sdr_hash_compute,
449 ipmi_sdr_hash_compare)) == NULL)
450 return (-1);
451
452 return (0);
453 }
454
455 void
ipmi_sdr_clear(ipmi_handle_t * ihp)456 ipmi_sdr_clear(ipmi_handle_t *ihp)
457 {
458 ipmi_sdr_cache_ent_t *ent;
459
460 while ((ent = ipmi_hash_first(ihp->ih_sdr_cache)) != NULL) {
461 ipmi_hash_remove(ihp->ih_sdr_cache, ent);
462 ipmi_free(ihp, ent->isc_sdr);
463 ipmi_free(ihp, ent->isc_name);
464 ipmi_free(ihp, ent);
465 }
466 }
467
468 void
ipmi_sdr_fini(ipmi_handle_t * ihp)469 ipmi_sdr_fini(ipmi_handle_t *ihp)
470 {
471 if (ihp->ih_sdr_cache != NULL) {
472 ipmi_sdr_clear(ihp);
473 ipmi_hash_destroy(ihp->ih_sdr_cache);
474 }
475 }
476
477 ipmi_sdr_t *
ipmi_sdr_get(ipmi_handle_t * ihp,uint16_t id,uint16_t * next)478 ipmi_sdr_get(ipmi_handle_t *ihp, uint16_t id, uint16_t *next)
479 {
480 uint8_t offset = IPMI_SDR_HDR_SZ, count = 0, chunksz = 16, sdr_sz;
481 ipmi_cmd_t cmd, *rsp;
482 ipmi_cmd_get_sdr_t req;
483 ipmi_sdr_t *sdr;
484 int i = 0;
485 char *buf;
486
487 req.ic_gs_resid = ihp->ih_reservation;
488 req.ic_gs_recid = id;
489
490 cmd.ic_netfn = IPMI_NETFN_STORAGE;
491 cmd.ic_lun = 0;
492 cmd.ic_cmd = IPMI_CMD_GET_SDR;
493 cmd.ic_dlen = sizeof (req);
494 cmd.ic_data = &req;
495
496 /*
497 * The size of the SDR is contained in the 5th byte of the SDR header,
498 * so we'll read the first 5 bytes to get the size, so we know how big
499 * to make the buffer.
500 */
501 req.ic_gs_offset = 0;
502 req.ic_gs_len = IPMI_SDR_HDR_SZ;
503 for (i = 0; i < ihp->ih_retries; i++) {
504 if ((rsp = ipmi_send(ihp, &cmd)) != NULL)
505 break;
506
507 if (ipmi_errno(ihp) != EIPMI_INVALID_RESERVATION)
508 return (NULL);
509
510 if (ipmi_sdr_reserve_repository(ihp) != 0)
511 return (NULL);
512 req.ic_gs_resid = ihp->ih_reservation;
513 }
514 if (rsp == NULL)
515 return (NULL);
516
517 sdr = (ipmi_sdr_t *)((ipmi_rsp_get_sdr_t *)rsp->ic_data)->ir_gs_record;
518 sdr_sz = sdr->is_length;
519
520 if ((buf = ipmi_zalloc(ihp, sdr_sz + IPMI_SDR_HDR_SZ)) == NULL) {
521 (void) ipmi_set_error(ihp, EIPMI_NOMEM, NULL);
522 return (NULL);
523 }
524 (void) memcpy(buf, (void *)sdr, IPMI_SDR_HDR_SZ);
525
526 /*
527 * Some SDRs can be bigger than the buffer sizes for a given bmc
528 * interface. Therefore we break up the process of reading in an entire
529 * SDR into multiple smaller reads.
530 */
531 while (count < sdr_sz) {
532 req.ic_gs_offset = offset;
533 if (chunksz > (sdr_sz - count))
534 chunksz = sdr_sz - count;
535 req.ic_gs_len = chunksz;
536 rsp = ipmi_send(ihp, &cmd);
537
538 if (rsp != NULL) {
539 count += chunksz;
540 sdr = (ipmi_sdr_t *)
541 ((ipmi_rsp_get_sdr_t *)rsp->ic_data)->ir_gs_record;
542 (void) memcpy(buf+offset, (void *)sdr, chunksz);
543 offset += chunksz;
544 i = 0;
545 } else if (ipmi_errno(ihp) == EIPMI_INVALID_RESERVATION) {
546 if (i >= ihp->ih_retries ||
547 ipmi_sdr_reserve_repository(ihp) != 0) {
548 free(buf);
549 return (NULL);
550 }
551 req.ic_gs_resid = ihp->ih_reservation;
552 i++;
553 } else {
554 free(buf);
555 return (NULL);
556 }
557 }
558 *next = ((ipmi_rsp_get_sdr_t *)rsp->ic_data)->ir_gs_next;
559
560 return ((ipmi_sdr_t *)buf);
561 }
562
563 int
ipmi_sdr_iter(ipmi_handle_t * ihp,int (* func)(ipmi_handle_t *,const char *,ipmi_sdr_t *,void *),void * data)564 ipmi_sdr_iter(ipmi_handle_t *ihp, int (*func)(ipmi_handle_t *,
565 const char *, ipmi_sdr_t *, void *), void *data)
566 {
567 ipmi_sdr_cache_ent_t *ent;
568 int ret;
569
570 if (ipmi_hash_first(ihp->ih_sdr_cache) == NULL &&
571 ipmi_sdr_refresh(ihp) != 0)
572 return (-1);
573
574 for (ent = ipmi_hash_first(ihp->ih_sdr_cache); ent != NULL;
575 ent = ipmi_hash_next(ihp->ih_sdr_cache, ent)) {
576 if ((ret = func(ihp, ent->isc_name, ent->isc_sdr, data)) != 0)
577 return (ret);
578 }
579
580 return (0);
581 }
582
583 ipmi_sdr_t *
ipmi_sdr_lookup(ipmi_handle_t * ihp,const char * idstr)584 ipmi_sdr_lookup(ipmi_handle_t *ihp, const char *idstr)
585 {
586 return (ipmi_sdr_lookup_precise(ihp, idstr, IPMI_ET_UNSPECIFIED, 0));
587 }
588
589 ipmi_sdr_t *
ipmi_sdr_lookup_precise(ipmi_handle_t * ihp,const char * idstr,uint8_t e_id,uint8_t e_inst)590 ipmi_sdr_lookup_precise(ipmi_handle_t *ihp, const char *idstr, uint8_t e_id,
591 uint8_t e_inst)
592 {
593 ipmi_sdr_cache_ent_t *ent, search;
594
595 if (ipmi_hash_first(ihp->ih_sdr_cache) == NULL &&
596 ipmi_sdr_refresh(ihp) != 0)
597 return (NULL);
598
599 search.isc_name = (char *)idstr;
600 search.isc_sdr = NULL;
601 search.isc_entity_id = e_id;
602 search.isc_entity_inst = e_inst;
603 if ((ent = ipmi_hash_lookup(ihp->ih_sdr_cache, &search)) == NULL) {
604 (void) ipmi_set_error(ihp, EIPMI_NOT_PRESENT, NULL);
605 return (NULL);
606 }
607
608 return (ent->isc_sdr);
609 }
610
611 static void *
ipmi_sdr_lookup_common(ipmi_handle_t * ihp,const char * idstr,uint8_t type)612 ipmi_sdr_lookup_common(ipmi_handle_t *ihp, const char *idstr,
613 uint8_t type)
614 {
615 ipmi_sdr_t *sdrp;
616
617 if ((sdrp = ipmi_sdr_lookup(ihp, idstr)) == NULL)
618 return (NULL);
619
620 if (sdrp->is_type != type) {
621 (void) ipmi_set_error(ihp, EIPMI_NOT_PRESENT, NULL);
622 return (NULL);
623 }
624
625 return (sdrp->is_record);
626 }
627
628 ipmi_sdr_fru_locator_t *
ipmi_sdr_lookup_fru(ipmi_handle_t * ihp,const char * idstr)629 ipmi_sdr_lookup_fru(ipmi_handle_t *ihp, const char *idstr)
630 {
631 return (ipmi_sdr_lookup_common(ihp, idstr,
632 IPMI_SDR_TYPE_FRU_LOCATOR));
633 }
634
635 ipmi_sdr_generic_locator_t *
ipmi_sdr_lookup_generic(ipmi_handle_t * ihp,const char * idstr)636 ipmi_sdr_lookup_generic(ipmi_handle_t *ihp, const char *idstr)
637 {
638 return (ipmi_sdr_lookup_common(ihp, idstr,
639 IPMI_SDR_TYPE_GENERIC_LOCATOR));
640 }
641
642 ipmi_sdr_compact_sensor_t *
ipmi_sdr_lookup_compact_sensor(ipmi_handle_t * ihp,const char * idstr)643 ipmi_sdr_lookup_compact_sensor(ipmi_handle_t *ihp, const char *idstr)
644 {
645 return (ipmi_sdr_lookup_common(ihp, idstr,
646 IPMI_SDR_TYPE_COMPACT_SENSOR));
647 }
648
649 ipmi_sdr_full_sensor_t *
ipmi_sdr_lookup_full_sensor(ipmi_handle_t * ihp,const char * idstr)650 ipmi_sdr_lookup_full_sensor(ipmi_handle_t *ihp, const char *idstr)
651 {
652 return (ipmi_sdr_lookup_common(ihp, idstr,
653 IPMI_SDR_TYPE_FULL_SENSOR));
654 }
655
656 /*
657 * Mostly taken from ipmitool source v1.88
658 *
659 * This function converts the raw sensor reading returned by
660 * ipmi_get_sensor_reading to a unit-based value of type double.
661 */
662 int
ipmi_sdr_conv_reading(ipmi_sdr_full_sensor_t * sensor,uint8_t val,double * result)663 ipmi_sdr_conv_reading(ipmi_sdr_full_sensor_t *sensor, uint8_t val,
664 double *result)
665 {
666 int m, b, k1, k2;
667
668 m = __TO_M(sensor->is_fs_mtol);
669 b = __TO_B(sensor->is_fs_bacc);
670 k1 = __TO_B_EXP(sensor->is_fs_bacc);
671 k2 = __TO_R_EXP(sensor->is_fs_bacc);
672
673 switch (sensor->is_fs_analog_fmt) {
674 case IPMI_DATA_FMT_UNSIGNED:
675 *result = (double)(((m * val) +
676 (b * pow(10, k1))) * pow(10, k2));
677 break;
678 case IPMI_DATA_FMT_ONESCOMP:
679 if (val & 0x80)
680 val++;
681 /* FALLTHRU */
682 case IPMI_DATA_FMT_TWOSCOMP:
683 *result = (double)(((m * (int8_t)val) +
684 (b * pow(10, k1))) * pow(10, k2));
685 break;
686 default:
687 /* This sensor does not return a numeric reading */
688 return (-1);
689 }
690
691 switch (sensor->is_fs_sensor_linear_type) {
692 case SDR_SENSOR_L_LN:
693 *result = log(*result);
694 break;
695 case SDR_SENSOR_L_LOG10:
696 *result = log10(*result);
697 break;
698 case SDR_SENSOR_L_LOG2:
699 *result = (double)(log(*result) / log(2.0));
700 break;
701 case SDR_SENSOR_L_E:
702 *result = exp(*result);
703 break;
704 case SDR_SENSOR_L_EXP10:
705 *result = pow(10.0, *result);
706 break;
707 case SDR_SENSOR_L_EXP2:
708 *result = pow(2.0, *result);
709 break;
710 case SDR_SENSOR_L_1_X:
711 *result = pow(*result, -1.0); /* 1/x w/o exception */
712 break;
713 case SDR_SENSOR_L_SQR:
714 *result = pow(*result, 2.0);
715 break;
716 case SDR_SENSOR_L_CUBE:
717 *result = pow(*result, 3.0);
718 break;
719 case SDR_SENSOR_L_SQRT:
720 *result = sqrt(*result);
721 break;
722 case SDR_SENSOR_L_CUBERT:
723 *result = cbrt(*result);
724 break;
725 case SDR_SENSOR_L_LINEAR:
726 default:
727 break;
728 }
729 return (0);
730 }
731