xref: /openbmc/ipmitool/lib/ipmi_sdr.c (revision 6ca88cb6)
1 /*
2  * Copyright (c) 2012 Hewlett-Packard Development Company, L.P.
3  *
4  * Based on code from
5  * Copyright (c) 2003 Sun Microsystems, Inc.  All Rights Reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  *
11  * Redistribution of source code must retain the above copyright
12  * notice, this list of conditions and the following disclaimer.
13  *
14  * Redistribution in binary form must reproduce the above copyright
15  * notice, this list of conditions and the following disclaimer in the
16  * documentation and/or other materials provided with the distribution.
17  *
18  * Neither the name of Sun Microsystems, Inc. or the names of
19  * contributors may be used to endorse or promote products derived
20  * from this software without specific prior written permission.
21  *
22  * This software is provided "AS IS," without a warranty of any kind.
23  * ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES,
24  * INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A
25  * PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED.
26  * SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL NOT BE LIABLE
27  * FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING
28  * OR DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES.  IN NO EVENT WILL
29  * SUN OR ITS LICENSORS BE LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA,
30  * OR FOR DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL OR
31  * PUNITIVE DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY OF
32  * LIABILITY, ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE,
33  * EVEN IF SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
34  */
35 
36 #include <string.h>
37 
38 #include <math.h>
39 #include <stdio.h>
40 #include <unistd.h>
41 #include <sys/types.h>
42 #include <time.h>
43 
44 #include <ipmitool/ipmi.h>
45 #include <ipmitool/log.h>
46 #include <ipmitool/ipmi_mc.h>
47 #include <ipmitool/ipmi_sdr.h>
48 #include <ipmitool/ipmi_sdradd.h>
49 #include <ipmitool/ipmi_sensor.h>
50 #include <ipmitool/ipmi_intf.h>
51 #include <ipmitool/ipmi_sel.h>
52 #include <ipmitool/ipmi_entity.h>
53 #include <ipmitool/ipmi_constants.h>
54 #include <ipmitool/ipmi_strings.h>
55 
56 #if HAVE_CONFIG_H
57 # include <config.h>
58 #endif
59 
60 extern int verbose;
61 static int use_built_in;	/* Uses DeviceSDRs instead of SDRR */
62 static int sdr_max_read_len = 0;
63 static int sdr_extended = 0;
64 static long sdriana = 0;
65 
66 static struct sdr_record_list *sdr_list_head = NULL;
67 static struct sdr_record_list *sdr_list_tail = NULL;
68 static struct ipmi_sdr_iterator *sdr_list_itr = NULL;
69 
70 void printf_sdr_usage();
71 
72 /* ipmi_sdr_get_unit_string  -  return units for base/modifier
73  *
74  * @pct:	units are a percentage
75  * @type:	unit type
76  * @base:	base
77  * @modifier:	modifier
78  *
79  * returns pointer to static string
80  */
81 const char *
82 ipmi_sdr_get_unit_string(uint8_t pct, uint8_t type, uint8_t base, uint8_t modifier)
83 {
84 	static char unitstr[16];
85 	/*
86 	 * By default, if units are supposed to be percent, we will pre-pend
87 	 * the percent string  to the textual representation of the units.
88 	 */
89 	char *pctstr = pct ? "% " : "";
90 	memset(unitstr, 0, sizeof (unitstr));
91 	switch (type) {
92 	case 2:
93 		snprintf(unitstr, sizeof (unitstr), "%s%s * %s",
94 			 pctstr, unit_desc[base], unit_desc[modifier]);
95 		break;
96 	case 1:
97 		snprintf(unitstr, sizeof (unitstr), "%s%s/%s",
98 			 pctstr, unit_desc[base], unit_desc[modifier]);
99 		break;
100 	case 0:
101 	default:
102 		/*
103 		 * Display the text "percent" only when the Base unit is
104 		 * "unspecified" and the caller specified to print percent.
105 		 */
106 		if (base == 0 && pct) {
107 			snprintf(unitstr, sizeof(unitstr), "percent");
108 		} else {
109 			snprintf(unitstr, sizeof (unitstr), "%s%s",
110 				pctstr, unit_desc[base]);
111 		}
112 		break;
113 	}
114 	return unitstr;
115 }
116 
117 /* sdr_sensor_has_analog_reading  -  Determine if sensor has an analog reading
118  *
119  */
120 static int
121 sdr_sensor_has_analog_reading(struct ipmi_intf *intf,
122 			    struct sensor_reading *sr)
123 {
124 	/* Compact sensors can't return analog values so we false */
125 	if (!sr->full) {
126 		return 0;
127 	}
128 	/*
129 	 * Per the IPMI Specification:
130 	 *	Only Full Threshold sensors are identified as providing
131 	 *	analog readings.
132 	 *
133 	 * But... HP didn't interpret this as meaning that "Only Threshold
134 	 *        Sensors" can provide analog readings.  So, HP packed analog
135 	 *        readings into some of their non-Threshold Sensor.   There is
136 	 *	  nothing that explictly prohibits this in the spec, so if
137 	 *	  an Analog reading is available in a Non-Threshod sensor and
138 	 *	  there are units specified for identifying the reading then
139 	 *	  we do an analog conversion even though the sensor is
140 	 *	  non-Threshold.   To be safe, we provide this extension for
141 	 *	  HP.
142 	 *
143 	 */
144 	if ( UNITS_ARE_DISCRETE(&sr->full->cmn) ) {
145 		return 0;/* Sensor specified as not having Analog Units */
146 	}
147 	if ( !IS_THRESHOLD_SENSOR(&sr->full->cmn) ) {
148 		/* Non-Threshold Sensors are not defined as having analog */
149 		/* But.. We have one with defined with Analog Units */
150 		if ( (sr->full->cmn.unit.pct | sr->full->cmn.unit.modifier |
151 			 sr->full->cmn.unit.type.base |
152 			 sr->full->cmn.unit.type.modifier)) {
153 			 /* And it does have the necessary units specs */
154 			 if ( !(intf->manufacturer_id == IPMI_OEM_HP) ) {
155 				/* But to be safe we only do this for HP */
156 				return 0;
157 			 }
158 		} else {
159 			return 0;
160 		}
161 	}
162 	/*
163 	 * If sensor has linearization, then we should be able to update the
164 	 * reading factors and if we cannot fail the conversion.
165 	 */
166 	if (sr->full->linearization >= SDR_SENSOR_L_NONLINEAR &&
167 	    sr->full->linearization <= 0x7F) {
168 		if (ipmi_sensor_get_sensor_reading_factors(intf, sr->full, sr->s_reading) < 0){
169 			sr->s_reading_valid = 0;
170 			return 0;
171 		}
172 	}
173 
174 	return 1;
175 }
176 
177 /* sdr_convert_sensor_reading  -  convert raw sensor reading
178  *
179  * @sensor:	sensor record
180  * @val:	raw sensor reading
181  *
182  * returns floating-point sensor reading
183  */
184 double
185 sdr_convert_sensor_reading(struct sdr_record_full_sensor *sensor, uint8_t val)
186 {
187 	int m, b, k1, k2;
188 	double result;
189 
190 	m = __TO_M(sensor->mtol);
191 	b = __TO_B(sensor->bacc);
192 	k1 = __TO_B_EXP(sensor->bacc);
193 	k2 = __TO_R_EXP(sensor->bacc);
194 
195 	switch (sensor->cmn.unit.analog) {
196 	case 0:
197 		result = (double) (((m * val) +
198 				    (b * pow(10, k1))) * pow(10, k2));
199 		break;
200 	case 1:
201 		if (val & 0x80)
202 			val++;
203 		/* Deliberately fall through to case 2. */
204 	case 2:
205 		result = (double) (((m * (int8_t) val) +
206 				    (b * pow(10, k1))) * pow(10, k2));
207 		break;
208 	default:
209 		/* Oops! This isn't an analog sensor. */
210 		return 0.0;
211 	}
212 
213 	switch (sensor->linearization & 0x7f) {
214 	case SDR_SENSOR_L_LN:
215 		result = log(result);
216 		break;
217 	case SDR_SENSOR_L_LOG10:
218 		result = log10(result);
219 		break;
220 	case SDR_SENSOR_L_LOG2:
221 		result = (double) (log(result) / log(2.0));
222 		break;
223 	case SDR_SENSOR_L_E:
224 		result = exp(result);
225 		break;
226 	case SDR_SENSOR_L_EXP10:
227 		result = pow(10.0, result);
228 		break;
229 	case SDR_SENSOR_L_EXP2:
230 		result = pow(2.0, result);
231 		break;
232 	case SDR_SENSOR_L_1_X:
233 		result = pow(result, -1.0);	/*1/x w/o exception */
234 		break;
235 	case SDR_SENSOR_L_SQR:
236 		result = pow(result, 2.0);
237 		break;
238 	case SDR_SENSOR_L_CUBE:
239 		result = pow(result, 3.0);
240 		break;
241 	case SDR_SENSOR_L_SQRT:
242 		result = sqrt(result);
243 		break;
244 	case SDR_SENSOR_L_CUBERT:
245 		result = cbrt(result);
246 		break;
247 	case SDR_SENSOR_L_LINEAR:
248 	default:
249 		break;
250 	}
251 	return result;
252 }
253 /* sdr_convert_sensor_hysterisis  -  convert raw sensor hysterisis
254  *
255  * Even though spec says histerisis should be computed using Mx+B
256  * formula, B is irrelevant when doing raw comparison
257  *
258  * threshold rearm point is computed using threshold +/- hysterisis
259  * with the full formula however B can't be applied in raw comparisons
260  *
261  * @sensor:	sensor record
262  * @val:	raw sensor reading
263  *
264  * returns floating-point sensor reading
265  */
266 double
267 sdr_convert_sensor_hysterisis(struct sdr_record_full_sensor *sensor, uint8_t val)
268 {
269 	int m, k2;
270 	double result;
271 
272 	m = __TO_M(sensor->mtol);
273 
274 	k2 = __TO_R_EXP(sensor->bacc);
275 
276 	switch (sensor->cmn.unit.analog) {
277 	case 0:
278 		result = (double) (((m * val)) * pow(10, k2));
279 		break;
280 	case 1:
281 		if (val & 0x80)
282 			val++;
283 		/* Deliberately fall through to case 2. */
284 	case 2:
285 		result = (double) (((m * (int8_t) val) ) * pow(10, k2));
286 		break;
287 	default:
288 		/* Oops! This isn't an analog sensor. */
289 		return 0.0;
290 	}
291 
292 	switch (sensor->linearization & 0x7f) {
293 	case SDR_SENSOR_L_LN:
294 		result = log(result);
295 		break;
296 	case SDR_SENSOR_L_LOG10:
297 		result = log10(result);
298 		break;
299 	case SDR_SENSOR_L_LOG2:
300 		result = (double) (log(result) / log(2.0));
301 		break;
302 	case SDR_SENSOR_L_E:
303 		result = exp(result);
304 		break;
305 	case SDR_SENSOR_L_EXP10:
306 		result = pow(10.0, result);
307 		break;
308 	case SDR_SENSOR_L_EXP2:
309 		result = pow(2.0, result);
310 		break;
311 	case SDR_SENSOR_L_1_X:
312 		result = pow(result, -1.0);	/*1/x w/o exception */
313 		break;
314 	case SDR_SENSOR_L_SQR:
315 		result = pow(result, 2.0);
316 		break;
317 	case SDR_SENSOR_L_CUBE:
318 		result = pow(result, 3.0);
319 		break;
320 	case SDR_SENSOR_L_SQRT:
321 		result = sqrt(result);
322 		break;
323 	case SDR_SENSOR_L_CUBERT:
324 		result = cbrt(result);
325 		break;
326 	case SDR_SENSOR_L_LINEAR:
327 	default:
328 		break;
329 	}
330 	return result;
331 }
332 
333 
334 /* sdr_convert_sensor_tolerance  -  convert raw sensor reading
335  *
336  * @sensor:	sensor record
337  * @val:	raw sensor reading
338  *
339  * returns floating-point sensor tolerance(interpreted)
340  */
341 double
342 sdr_convert_sensor_tolerance(struct sdr_record_full_sensor *sensor, uint8_t val)
343 {
344 	int m,   k2;
345 	double result;
346 
347 	m = __TO_M(sensor->mtol);
348 	k2 = __TO_R_EXP(sensor->bacc);
349 
350 	switch (sensor->cmn.unit.analog) {
351 	case 0:
352                 /* as suggested in section 30.4.1 of IPMI 1.5 spec */
353 		result = (double) ((((m * (double)val/2)) ) * pow(10, k2));
354 		break;
355 	case 1:
356 		if (val & 0x80)
357 			val++;
358 		/* Deliberately fall through to case 2. */
359 	case 2:
360 		result = (double) (((m * ((double)((int8_t) val)/2))) * pow(10, k2));
361 		break;
362 	default:
363 		/* Oops! This isn't an analog sensor. */
364 		return 0.0;
365 	}
366 
367 	switch (sensor->linearization & 0x7f) {
368 	case SDR_SENSOR_L_LN:
369 		result = log(result);
370 		break;
371 	case SDR_SENSOR_L_LOG10:
372 		result = log10(result);
373 		break;
374 	case SDR_SENSOR_L_LOG2:
375 		result = (double) (log(result) / log(2.0));
376 		break;
377 	case SDR_SENSOR_L_E:
378 		result = exp(result);
379 		break;
380 	case SDR_SENSOR_L_EXP10:
381 		result = pow(10.0, result);
382 		break;
383 	case SDR_SENSOR_L_EXP2:
384 		result = pow(2.0, result);
385 		break;
386 	case SDR_SENSOR_L_1_X:
387 		result = pow(result, -1.0);	/*1/x w/o exception */
388 		break;
389 	case SDR_SENSOR_L_SQR:
390 		result = pow(result, 2.0);
391 		break;
392 	case SDR_SENSOR_L_CUBE:
393 		result = pow(result, 3.0);
394 		break;
395 	case SDR_SENSOR_L_SQRT:
396 		result = sqrt(result);
397 		break;
398 	case SDR_SENSOR_L_CUBERT:
399 		result = cbrt(result);
400 		break;
401 	case SDR_SENSOR_L_LINEAR:
402 	default:
403 		break;
404 	}
405 	return result;
406 }
407 
408 /* sdr_convert_sensor_value_to_raw  -  convert sensor reading back to raw
409  *
410  * @sensor:	sensor record
411  * @val:	converted sensor reading
412  *
413  * returns raw sensor reading
414  */
415 uint8_t
416 sdr_convert_sensor_value_to_raw(struct sdr_record_full_sensor * sensor,
417 				double val)
418 {
419 	int m, b, k1, k2;
420 	double result;
421 
422 	/* only works for analog sensors */
423 	if (UNITS_ARE_DISCRETE((&sensor->cmn)))
424 		return 0;
425 
426 	m = __TO_M(sensor->mtol);
427 	b = __TO_B(sensor->bacc);
428 	k1 = __TO_B_EXP(sensor->bacc);
429 	k2 = __TO_R_EXP(sensor->bacc);
430 
431 	/* don't divide by zero */
432 	if (m == 0)
433 		return 0;
434 
435 	result = (((val / pow(10, k2)) - (b * pow(10, k1))) / m);
436 
437 	if ((result - (int) result) >= .5)
438 		return (uint8_t) ceil(result);
439 	else
440 		return (uint8_t) result;
441 }
442 
443 /* ipmi_sdr_get_sensor_thresholds  -  return thresholds for sensor
444  *
445  * @intf:	ipmi interface
446  * @sensor:	sensor number
447  * @target:	sensor owner ID
448  * @lun:	sensor lun
449  * @channel:	channel number
450  *
451  * returns pointer to ipmi response
452  */
453 struct ipmi_rs *
454 ipmi_sdr_get_sensor_thresholds(struct ipmi_intf *intf, uint8_t sensor,
455 					uint8_t target, uint8_t lun, uint8_t channel)
456 {
457 	struct ipmi_rq req;
458 	struct ipmi_rs *rsp;
459 	uint8_t  bridged_request = 0;
460 	uint32_t save_addr;
461 	uint32_t save_channel;
462 
463 	if ( BRIDGE_TO_SENSOR(intf, target, channel) ) {
464 		bridged_request = 1;
465 		save_addr = intf->target_addr;
466 		intf->target_addr = target;
467 		save_channel = intf->target_channel;
468 		intf->target_channel = channel;
469 	}
470 
471 	memset(&req, 0, sizeof (req));
472 	req.msg.netfn = IPMI_NETFN_SE;
473 	req.msg.lun = lun;
474 	req.msg.cmd = GET_SENSOR_THRESHOLDS;
475 	req.msg.data = &sensor;
476 	req.msg.data_len = sizeof (sensor);
477 
478 	rsp = intf->sendrecv(intf, &req);
479 	if (bridged_request) {
480 		intf->target_addr = save_addr;
481 		intf->target_channel = save_channel;
482 	}
483 	return rsp;
484 }
485 
486 /* ipmi_sdr_get_sensor_hysteresis  -  return hysteresis for sensor
487  *
488  * @intf:	ipmi interface
489  * @sensor:	sensor number
490  * @target:	sensor owner ID
491  * @lun:	sensor lun
492  * @channel:	channel number
493  *
494  * returns pointer to ipmi response
495  */
496 struct ipmi_rs *
497 ipmi_sdr_get_sensor_hysteresis(struct ipmi_intf *intf, uint8_t sensor,
498 					uint8_t target, uint8_t lun, uint8_t channel)
499 {
500 	struct ipmi_rq req;
501 	uint8_t rqdata[2];
502 	struct ipmi_rs *rsp;
503 	uint8_t  bridged_request = 0;
504 	uint32_t save_addr;
505 	uint32_t save_channel;
506 
507 	if ( BRIDGE_TO_SENSOR(intf, target, channel) ) {
508 		bridged_request = 1;
509 		save_addr = intf->target_addr;
510 		intf->target_addr = target;
511 		save_channel = intf->target_channel;
512 		intf->target_channel = channel;
513 	}
514 
515 	rqdata[0] = sensor;
516 	rqdata[1] = 0xff;	/* reserved */
517 
518 	memset(&req, 0, sizeof (req));
519 	req.msg.netfn = IPMI_NETFN_SE;
520 	req.msg.lun = lun;
521 	req.msg.cmd = GET_SENSOR_HYSTERESIS;
522 	req.msg.data = rqdata;
523 	req.msg.data_len = 2;
524 
525 	rsp = intf->sendrecv(intf, &req);
526 	if (bridged_request) {
527 		intf->target_addr = save_addr;
528 		intf->target_channel = save_channel;
529 	}
530 	return rsp;
531 }
532 
533 /* ipmi_sdr_get_sensor_reading  -  retrieve a raw sensor reading
534  *
535  * @intf:	ipmi interface
536  * @sensor:	sensor id
537  *
538  * returns ipmi response structure
539  */
540 struct ipmi_rs *
541 ipmi_sdr_get_sensor_reading(struct ipmi_intf *intf, uint8_t sensor)
542 {
543 	struct ipmi_rq req;
544 
545 	memset(&req, 0, sizeof (req));
546 	req.msg.netfn = IPMI_NETFN_SE;
547 	req.msg.cmd = GET_SENSOR_READING;
548 	req.msg.data = &sensor;
549 	req.msg.data_len = 1;
550 
551 	return intf->sendrecv(intf, &req);
552 }
553 
554 
555 /* ipmi_sdr_get_sensor_reading_ipmb  -  retrieve a raw sensor reading from ipmb
556  *
557  * @intf:	ipmi interface
558  * @sensor:	sensor id
559  * @target:	IPMB target address
560  * @lun:	sensor lun
561  * @channel:	channel number
562  *
563  * returns ipmi response structure
564  */
565 struct ipmi_rs *
566 ipmi_sdr_get_sensor_reading_ipmb(struct ipmi_intf *intf, uint8_t sensor,
567 				 uint8_t target, uint8_t lun, uint8_t channel)
568 {
569 	struct ipmi_rq req;
570 	struct ipmi_rs *rsp;
571 	uint8_t  bridged_request = 0;
572 	uint32_t save_addr;
573 	uint32_t save_channel;
574 
575 	if ( BRIDGE_TO_SENSOR(intf, target, channel) ) {
576 		lprintf(LOG_DEBUG,
577 			"Bridge to Sensor "
578 			"Intf my/%#x tgt/%#x:%#x Sdr tgt/%#x:%#x\n",
579 			intf->my_addr, intf->target_addr, intf->target_channel,
580 			target, channel);
581 		bridged_request = 1;
582 		save_addr = intf->target_addr;
583 		intf->target_addr = target;
584 		save_channel = intf->target_channel;
585 		intf->target_channel = channel;
586 	}
587 	memset(&req, 0, sizeof (req));
588 	req.msg.netfn = IPMI_NETFN_SE;
589 	req.msg.lun = lun;
590 	req.msg.cmd = GET_SENSOR_READING;
591 	req.msg.data = &sensor;
592 	req.msg.data_len = 1;
593 
594 	rsp = intf->sendrecv(intf, &req);
595 	if (bridged_request) {
596 		intf->target_addr    = save_addr;
597 		intf->target_channel = save_channel;
598 	}
599 	return rsp;
600 }
601 
602 /* ipmi_sdr_get_sensor_event_status  -  retrieve sensor event status
603  *
604  * @intf:	ipmi interface
605  * @sensor:	sensor id
606  * @target:	sensor owner ID
607  * @lun:	sensor lun
608  * @channel:	channel number
609  *
610  * returns ipmi response structure
611  */
612 struct ipmi_rs *
613 ipmi_sdr_get_sensor_event_status(struct ipmi_intf *intf, uint8_t sensor,
614 				 uint8_t target, uint8_t lun, uint8_t channel)
615 {
616 	struct ipmi_rq req;
617 	struct ipmi_rs *rsp;
618 	uint8_t  bridged_request = 0;
619 	uint32_t save_addr;
620 	uint32_t save_channel;
621 
622 	if ( BRIDGE_TO_SENSOR(intf, target, channel) ) {
623 		bridged_request = 1;
624 		save_addr = intf->target_addr;
625 		intf->target_addr = target;
626 		save_channel = intf->target_channel;
627 		intf->target_channel = channel;
628 	}
629 	memset(&req, 0, sizeof (req));
630 	req.msg.netfn = IPMI_NETFN_SE;
631 	req.msg.lun = lun;
632 	req.msg.cmd = GET_SENSOR_EVENT_STATUS;
633 	req.msg.data = &sensor;
634 	req.msg.data_len = 1;
635 
636 	rsp = intf->sendrecv(intf, &req);
637 	if (bridged_request) {
638 		intf->target_addr = save_addr;
639 		intf->target_channel = save_channel;
640 	}
641 	return rsp;
642 }
643 
644 /* ipmi_sdr_get_sensor_event_enable  -  retrieve sensor event enables
645  *
646  * @intf:	ipmi interface
647  * @sensor:	sensor id
648  * @target:	sensor owner ID
649  * @lun:	sensor lun
650  * @channel:	channel number
651  *
652  * returns ipmi response structure
653  */
654 struct ipmi_rs *
655 ipmi_sdr_get_sensor_event_enable(struct ipmi_intf *intf, uint8_t sensor,
656 				 uint8_t target, uint8_t lun, uint8_t channel)
657 {
658 	struct ipmi_rq req;
659 	struct ipmi_rs *rsp;
660 	uint8_t  bridged_request = 0;
661 	uint32_t save_addr;
662 	uint32_t save_channel;
663 
664 	if ( BRIDGE_TO_SENSOR(intf, target, channel) ) {
665 		bridged_request = 1;
666 		save_addr = intf->target_addr;
667 		intf->target_addr = target;
668 		save_channel = intf->target_channel;
669 		intf->target_channel = channel;
670 	}
671 
672 	memset(&req, 0, sizeof (req));
673 	req.msg.netfn = IPMI_NETFN_SE;
674 	req.msg.lun = lun;
675 	req.msg.cmd = GET_SENSOR_EVENT_ENABLE;
676 	req.msg.data = &sensor;
677 	req.msg.data_len = 1;
678 
679 	rsp = intf->sendrecv(intf, &req);
680 	if (bridged_request) {
681 		intf->target_addr = save_addr;
682 		intf->target_channel = save_channel;
683 	}
684 	return rsp;
685 }
686 
687 /* ipmi_sdr_get_sensor_type_desc  -  Get sensor type descriptor
688  *
689  * @type:	ipmi sensor type
690  *
691  * returns
692  *   string from sensor_type_desc
693  *   or "reserved"
694  *   or "OEM reserved"
695  */
696 const char *
697 ipmi_sdr_get_sensor_type_desc(const uint8_t type)
698 {
699 	static char desc[32];
700 	memset(desc, 0, 32);
701 	if (type <= SENSOR_TYPE_MAX)
702 		return sensor_type_desc[type];
703 	if (type < 0xc0)
704 		snprintf(desc, 32, "reserved #%02x", type);
705 	else
706    {
707       snprintf(desc, 32, oemval2str(sdriana,type,ipmi_oem_sdr_type_vals),
708                                                                    type);
709    }
710 	return desc;
711 }
712 
713 /* ipmi_sdr_get_thresh_status  -  threshold status indicator
714  *
715  * @rsp:		response from Get Sensor Reading comand
716  * @validread:	validity of the status field argument
717  * @invalidstr:	string to return if status field is not valid
718  *
719  * returns
720  *   cr = critical
721  *   nc = non-critical
722  *   nr = non-recoverable
723  *   ok = ok
724  *   ns = not specified
725  */
726 const char *
727 ipmi_sdr_get_thresh_status(struct sensor_reading *sr, const char *invalidstr)
728 {
729 	uint8_t stat;
730 	if (!sr->s_reading_valid) {
731 	    return invalidstr;
732 	}
733 	stat = sr->s_data2;
734 	if (stat & SDR_SENSOR_STAT_LO_NR) {
735 		if (verbose)
736 			return "Lower Non-Recoverable";
737 		else if (sdr_extended)
738 			return "lnr";
739 		else
740 			return "nr";
741 	} else if (stat & SDR_SENSOR_STAT_HI_NR) {
742 		if (verbose)
743 			return "Upper Non-Recoverable";
744 		else if (sdr_extended)
745 			return "unr";
746 		else
747 			return "nr";
748 	} else if (stat & SDR_SENSOR_STAT_LO_CR) {
749 		if (verbose)
750 			return "Lower Critical";
751 		else if (sdr_extended)
752 			return "lcr";
753 		else
754 			return "cr";
755 	} else if (stat & SDR_SENSOR_STAT_HI_CR) {
756 		if (verbose)
757 			return "Upper Critical";
758 		else if (sdr_extended)
759 			return "ucr";
760 		else
761 			return "cr";
762 	} else if (stat & SDR_SENSOR_STAT_LO_NC) {
763 		if (verbose)
764 			return "Lower Non-Critical";
765 		else if (sdr_extended)
766 			return "lnc";
767 		else
768 			return "nc";
769 	} else if (stat & SDR_SENSOR_STAT_HI_NC) {
770 		if (verbose)
771 			return "Upper Non-Critical";
772 		else if (sdr_extended)
773 			return "unc";
774 		else
775 			return "nc";
776 	}
777 	return "ok";
778 }
779 
780 /* ipmi_sdr_get_header  -  retreive SDR record header
781  *
782  * @intf:	ipmi interface
783  * @itr:	sdr iterator
784  *
785  * returns pointer to static sensor retrieval struct
786  * returns NULL on error
787  */
788 static struct sdr_get_rs *
789 ipmi_sdr_get_header(struct ipmi_intf *intf, struct ipmi_sdr_iterator *itr)
790 {
791 	struct ipmi_rq req;
792 	struct ipmi_rs *rsp;
793 	struct sdr_get_rq sdr_rq;
794 	static struct sdr_get_rs sdr_rs;
795 	int try = 0;
796 
797 	memset(&sdr_rq, 0, sizeof (sdr_rq));
798 	sdr_rq.reserve_id = itr->reservation;
799 	sdr_rq.id = itr->next;
800 	sdr_rq.offset = 0;
801 	sdr_rq.length = 5;	/* only get the header */
802 
803 	memset(&req, 0, sizeof (req));
804 	if (itr->use_built_in == 0) {
805 		req.msg.netfn = IPMI_NETFN_STORAGE;
806 		req.msg.cmd = GET_SDR;
807 	} else {
808 		req.msg.netfn = IPMI_NETFN_SE;
809 		req.msg.cmd = GET_DEVICE_SDR;
810 	}
811 	req.msg.data = (uint8_t *) & sdr_rq;
812 	req.msg.data_len = sizeof (sdr_rq);
813 
814 	for (try = 0; try < 5; try++) {
815 		sdr_rq.reserve_id = itr->reservation;
816 		rsp = intf->sendrecv(intf, &req);
817 		if (rsp == NULL) {
818 			lprintf(LOG_ERR, "Get SDR %04x command failed",
819 				itr->next);
820 			continue;
821 		} else if (rsp->ccode == 0xc5) {
822 			/* lost reservation */
823 			lprintf(LOG_DEBUG, "SDR reservation %04x cancelled. "
824 				"Sleeping a bit and retrying...",
825 				itr->reservation);
826 
827 			sleep(rand() & 3);
828 
829 			if (ipmi_sdr_get_reservation(intf, itr->use_built_in,
830                                       &(itr->reservation)) < 0) {
831 				lprintf(LOG_ERR,
832 					"Unable to renew SDR reservation");
833 				return NULL;
834 			}
835 		} else if (rsp->ccode > 0) {
836 			lprintf(LOG_ERR, "Get SDR %04x command failed: %s",
837 				itr->next, val2str(rsp->ccode,
838 						   completion_code_vals));
839 			continue;
840 		} else {
841 			break;
842 		}
843 	}
844 
845    if (try == 5)
846       return NULL;
847 
848 	if (!rsp)
849 		return NULL;
850 
851 	lprintf(LOG_DEBUG, "SDR record ID   : 0x%04x", itr->next);
852 
853 	memcpy(&sdr_rs, rsp->data, sizeof (sdr_rs));
854 
855 	if (sdr_rs.length == 0) {
856 		lprintf(LOG_ERR, "SDR record id 0x%04x: invalid length %d",
857 			itr->next, sdr_rs.length);
858 		return NULL;
859 	}
860 
861 	/* achu (chu11 at llnl dot gov): - Some boards are stupid and
862 	 * return a record id from the Get SDR Record command
863 	 * different than the record id passed in.  If we find this
864 	 * situation, we cheat and put the original record id back in.
865 	 * Otherwise, a later Get SDR Record command will fail with
866 	 * completion code CBh = "Requested Sensor, data, or record
867 	 * not present"
868 	 */
869 	if (sdr_rs.id != itr->next) {
870 		lprintf(LOG_DEBUG, "SDR record id mismatch: 0x%04x", sdr_rs.id);
871 		sdr_rs.id = itr->next;
872 	}
873 
874 	lprintf(LOG_DEBUG, "SDR record type : 0x%02x", sdr_rs.type);
875 	lprintf(LOG_DEBUG, "SDR record next : 0x%04x", sdr_rs.next);
876 	lprintf(LOG_DEBUG, "SDR record bytes: %d", sdr_rs.length);
877 
878 	return &sdr_rs;
879 }
880 
881 /* ipmi_sdr_get_next_header  -  retreive next SDR header
882  *
883  * @intf:	ipmi interface
884  * @itr:	sdr iterator
885  *
886  * returns pointer to sensor retrieval struct
887  * returns NULL on error
888  */
889 struct sdr_get_rs *
890 ipmi_sdr_get_next_header(struct ipmi_intf *intf, struct ipmi_sdr_iterator *itr)
891 {
892 	struct sdr_get_rs *header;
893 
894 	if (itr->next == 0xffff)
895 		return NULL;
896 
897 	header = ipmi_sdr_get_header(intf, itr);
898 	if (header == NULL)
899 		return NULL;
900 
901 	itr->next = header->next;
902 
903 	return header;
904 }
905 
906 /*
907  * This macro is used to print nominal, normal and threshold settings,
908  * but it is not compatible with PRINT_NORMAL/PRINT_THRESH since it does
909  * not have the sensor.init.thresholds setting qualifier as is done in
910  * PRINT_THRESH.   This means CSV output can be different than non CSV
911  * output if sensor.init.thresholds is ever zero
912  */
913 /* helper macro for printing CSV output for Full SDR Threshold reading */
914 #define SENSOR_PRINT_CSV(FULLSENS, FLAG, READ)				\
915 	if ((FLAG)) {							\
916 		if (UNITS_ARE_DISCRETE((&FULLSENS->cmn)))		\
917 			printf("0x%02X,", READ); 			\
918 		else							\
919 			printf("%.3f,",	sdr_convert_sensor_reading(	\
920 			       (FULLSENS), READ));			\
921 	} else {							\
922 		printf(",");						\
923 	}
924 
925 /* helper macro for printing analog values for Full SDR Threshold readings */
926 #define SENSOR_PRINT_NORMAL(FULLSENS, NAME, READ)			\
927 	if ((FULLSENS)->analog_flag.READ != 0) {			\
928 		printf(" %-21s : ", NAME);				\
929 		if (UNITS_ARE_DISCRETE((&FULLSENS->cmn)))		\
930 			printf("0x%02X\n",				\
931 			       (FULLSENS)->READ);			\
932 		else							\
933 			printf("%.3f\n", sdr_convert_sensor_reading(	\
934 				         (FULLSENS), (FULLSENS)->READ));\
935 	}
936 
937 /* helper macro for printing Full SDR sensor Thresholds */
938 #define SENSOR_PRINT_THRESH(FULLSENS, NAME, READ, FLAG)			\
939 	if ((FULLSENS)->cmn.sensor.init.thresholds &&			\
940 	    (FULLSENS)->cmn.mask.type.threshold.read.FLAG != 0) {	\
941 		printf(" %-21s : ", NAME);				\
942 		if (UNITS_ARE_DISCRETE((&FULLSENS->cmn)))		\
943 			printf("0x%02X\n",				\
944 			       (FULLSENS)->threshold.READ);		\
945 		else                                        		\
946 			printf("%.3f\n", sdr_convert_sensor_reading(	\
947 			     (FULLSENS), (FULLSENS)->threshold.READ));	\
948 	}
949 
950 int
951 ipmi_sdr_print_sensor_event_status(struct ipmi_intf *intf,
952 				   uint8_t sensor_num,
953 				   uint8_t sensor_type,
954 				   uint8_t event_type, int numeric_fmt,
955 				   uint8_t target, uint8_t lun, uint8_t channel)
956 {
957 	struct ipmi_rs *rsp;
958 	int i;
959 	const struct valstr assert_cond_1[] = {
960 		{0x80, "unc+"},
961 		{0x40, "unc-"},
962 		{0x20, "lnr+"},
963 		{0x10, "lnr-"},
964 		{0x08, "lcr+"},
965 		{0x04, "lcr-"},
966 		{0x02, "lnc+"},
967 		{0x01, "lnc-"},
968 		{0x00, NULL},
969 	};
970 	const struct valstr assert_cond_2[] = {
971 		{0x08, "unr+"},
972 		{0x04, "unr-"},
973 		{0x02, "ucr+"},
974 		{0x01, "ucr-"},
975 		{0x00, NULL},
976 	};
977 
978 	rsp = ipmi_sdr_get_sensor_event_status(intf, sensor_num,
979 						target, lun, channel);
980 
981 	if (rsp == NULL) {
982 		lprintf(LOG_DEBUG,
983 			"Error reading event status for sensor #%02x",
984 			sensor_num);
985 		return -1;
986 	}
987 	if (rsp->ccode > 0) {
988 		lprintf(LOG_DEBUG,
989 			"Error reading event status for sensor #%02x: %s",
990 			sensor_num, val2str(rsp->ccode, completion_code_vals));
991 		return -1;
992 	}
993 	/* There is an assumption here that data_len >= 1 */
994 	if (IS_READING_UNAVAILABLE(rsp->data[0])) {
995 		printf(" Event Status          : Unavailable\n");
996 		return 0;
997 	}
998 	if (IS_SCANNING_DISABLED(rsp->data[0])) {
999 		//printf(" Event Status          : Scanning Disabled\n");
1000 		//return 0;
1001 	}
1002 	if (IS_EVENT_MSG_DISABLED(rsp->data[0])) {
1003 		printf(" Event Status          : Event Messages Disabled\n");
1004 		//return 0;
1005 	}
1006 
1007 	switch (numeric_fmt) {
1008 	case DISCRETE_SENSOR:
1009 		if (rsp->data_len == 2) {
1010 			ipmi_sdr_print_discrete_state("Assertion Events",
1011 						      sensor_type, event_type,
1012 						      rsp->data[1], 0);
1013 		} else if (rsp->data_len > 2) {
1014 			ipmi_sdr_print_discrete_state("Assertion Events",
1015 						      sensor_type, event_type,
1016 						      rsp->data[1],
1017 						      rsp->data[2]);
1018 		}
1019 		if (rsp->data_len == 4) {
1020 			ipmi_sdr_print_discrete_state("Deassertion Events",
1021 						      sensor_type, event_type,
1022 						      rsp->data[3], 0);
1023 		} else if (rsp->data_len > 4) {
1024 			ipmi_sdr_print_discrete_state("Deassertion Events",
1025 						      sensor_type, event_type,
1026 						      rsp->data[3],
1027 						      rsp->data[4]);
1028 		}
1029 		break;
1030 
1031 	case ANALOG_SENSOR:
1032 		printf(" Assertion Events      : ");
1033 		for (i = 0; i < 8; i++) {
1034 			if (rsp->data[1] & (1 << i))
1035 				printf("%s ", val2str(1 << i, assert_cond_1));
1036 		}
1037 		if (rsp->data_len > 2) {
1038 			for (i = 0; i < 4; i++) {
1039 				if (rsp->data[2] & (1 << i))
1040 					printf("%s ",
1041 					       val2str(1 << i, assert_cond_2));
1042 			}
1043 			printf("\n");
1044 			if ((rsp->data_len == 4 && rsp->data[3] != 0) ||
1045 			    (rsp->data_len > 4
1046 			     && (rsp->data[3] != 0 && rsp->data[4] != 0))) {
1047 				printf(" Deassertion Events    : ");
1048 				for (i = 0; i < 8; i++) {
1049 					if (rsp->data[3] & (1 << i))
1050 						printf("%s ",
1051 						       val2str(1 << i,
1052 							       assert_cond_1));
1053 				}
1054 				if (rsp->data_len > 4) {
1055 					for (i = 0; i < 4; i++) {
1056 						if (rsp->data[4] & (1 << i))
1057 							printf("%s ",
1058 							       val2str(1 << i,
1059 								       assert_cond_2));
1060 					}
1061 				}
1062 				printf("\n");
1063 			}
1064 		} else {
1065 			printf("\n");
1066 		}
1067 		break;
1068 
1069 	default:
1070 		break;
1071 	}
1072 
1073 	return 0;
1074 }
1075 
1076 static int
1077 ipmi_sdr_print_sensor_mask(struct sdr_record_mask *mask,
1078 			   uint8_t sensor_type,
1079 			   uint8_t event_type, int numeric_fmt)
1080 {
1081 	/* iceblink - don't print some event status fields - CVS rev1.53 */
1082 	return 0;
1083 
1084 	switch (numeric_fmt) {
1085 	case DISCRETE_SENSOR:
1086 		ipmi_sdr_print_discrete_state("Assert Event Mask", sensor_type,
1087 					      event_type,
1088 					      mask->type.discrete.
1089 					      assert_event & 0xff,
1090 					      (mask->type.discrete.
1091 					       assert_event & 0xff00) >> 8);
1092 		ipmi_sdr_print_discrete_state("Deassert Event Mask",
1093 					      sensor_type, event_type,
1094 					      mask->type.discrete.
1095 					      deassert_event & 0xff,
1096 					      (mask->type.discrete.
1097 					       deassert_event & 0xff00) >> 8);
1098 		break;
1099 
1100 	case ANALOG_SENSOR:
1101 		printf(" Assert Event Mask     : ");
1102 		if (mask->type.threshold.assert_lnr_high)
1103 			printf("lnr+ ");
1104 		if (mask->type.threshold.assert_lnr_low)
1105 			printf("lnr- ");
1106 		if (mask->type.threshold.assert_lcr_high)
1107 			printf("lcr+ ");
1108 		if (mask->type.threshold.assert_lcr_low)
1109 			printf("lcr- ");
1110 		if (mask->type.threshold.assert_lnc_high)
1111 			printf("lnc+ ");
1112 		if (mask->type.threshold.assert_lnc_low)
1113 			printf("lnc- ");
1114 		if (mask->type.threshold.assert_unc_high)
1115 			printf("unc+ ");
1116 		if (mask->type.threshold.assert_unc_low)
1117 			printf("unc- ");
1118 		if (mask->type.threshold.assert_ucr_high)
1119 			printf("ucr+ ");
1120 		if (mask->type.threshold.assert_ucr_low)
1121 			printf("ucr- ");
1122 		if (mask->type.threshold.assert_unr_high)
1123 			printf("unr+ ");
1124 		if (mask->type.threshold.assert_unr_low)
1125 			printf("unr- ");
1126 		printf("\n");
1127 
1128 		printf(" Deassert Event Mask   : ");
1129 		if (mask->type.threshold.deassert_lnr_high)
1130 			printf("lnr+ ");
1131 		if (mask->type.threshold.deassert_lnr_low)
1132 			printf("lnr- ");
1133 		if (mask->type.threshold.deassert_lcr_high)
1134 			printf("lcr+ ");
1135 		if (mask->type.threshold.deassert_lcr_low)
1136 			printf("lcr- ");
1137 		if (mask->type.threshold.deassert_lnc_high)
1138 			printf("lnc+ ");
1139 		if (mask->type.threshold.deassert_lnc_low)
1140 			printf("lnc- ");
1141 		if (mask->type.threshold.deassert_unc_high)
1142 			printf("unc+ ");
1143 		if (mask->type.threshold.deassert_unc_low)
1144 			printf("unc- ");
1145 		if (mask->type.threshold.deassert_ucr_high)
1146 			printf("ucr+ ");
1147 		if (mask->type.threshold.deassert_ucr_low)
1148 			printf("ucr- ");
1149 		if (mask->type.threshold.deassert_unr_high)
1150 			printf("unr+ ");
1151 		if (mask->type.threshold.deassert_unr_low)
1152 			printf("unr- ");
1153 		printf("\n");
1154 		break;
1155 
1156 	default:
1157 		break;
1158 	}
1159 
1160 	return 0;
1161 }
1162 
1163 int
1164 ipmi_sdr_print_sensor_event_enable(struct ipmi_intf *intf,
1165 				   uint8_t sensor_num,
1166 				   uint8_t sensor_type,
1167 				   uint8_t event_type, int numeric_fmt,
1168 				   uint8_t target, uint8_t lun, uint8_t channel)
1169 {
1170 	struct ipmi_rs *rsp;
1171 	int i;
1172 	const struct valstr assert_cond_1[] = {
1173 		{0x80, "unc+"},
1174 		{0x40, "unc-"},
1175 		{0x20, "lnr+"},
1176 		{0x10, "lnr-"},
1177 		{0x08, "lcr+"},
1178 		{0x04, "lcr-"},
1179 		{0x02, "lnc+"},
1180 		{0x01, "lnc-"},
1181 		{0x00, NULL},
1182 	};
1183 	const struct valstr assert_cond_2[] = {
1184 		{0x08, "unr+"},
1185 		{0x04, "unr-"},
1186 		{0x02, "ucr+"},
1187 		{0x01, "ucr-"},
1188 		{0x00, NULL},
1189 	};
1190 
1191 	rsp = ipmi_sdr_get_sensor_event_enable(intf, sensor_num,
1192 						target, lun, channel);
1193 
1194 	if (rsp == NULL) {
1195 		lprintf(LOG_DEBUG,
1196 			"Error reading event enable for sensor #%02x",
1197 			sensor_num);
1198 		return -1;
1199 	}
1200 	if (rsp->ccode > 0) {
1201 		lprintf(LOG_DEBUG,
1202 			"Error reading event enable for sensor #%02x: %s",
1203 			sensor_num, val2str(rsp->ccode, completion_code_vals));
1204 		return -1;
1205 	}
1206 
1207 	if (IS_SCANNING_DISABLED(rsp->data[0])) {
1208 		//printf(" Event Enable          : Scanning Disabled\n");
1209 		//return 0;
1210 	}
1211 	if (IS_EVENT_MSG_DISABLED(rsp->data[0])) {
1212 		printf(" Event Enable          : Event Messages Disabled\n");
1213 		//return 0;
1214 	}
1215 
1216 	switch (numeric_fmt) {
1217 	case DISCRETE_SENSOR:
1218 		/* discrete */
1219 		if (rsp->data_len == 2) {
1220 			ipmi_sdr_print_discrete_state("Assertions Enabled",
1221 						      sensor_type, event_type,
1222 						      rsp->data[1], 0);
1223 		} else if (rsp->data_len > 2) {
1224 			ipmi_sdr_print_discrete_state("Assertions Enabled",
1225 						      sensor_type, event_type,
1226 						      rsp->data[1],
1227 						      rsp->data[2]);
1228 		}
1229 		if (rsp->data_len == 4) {
1230 			ipmi_sdr_print_discrete_state("Deassertions Enabled",
1231 						      sensor_type, event_type,
1232 						      rsp->data[3], 0);
1233 		} else if (rsp->data_len > 4) {
1234 			ipmi_sdr_print_discrete_state("Deassertions Enabled",
1235 						      sensor_type, event_type,
1236 						      rsp->data[3],
1237 						      rsp->data[4]);
1238 		}
1239 		break;
1240 
1241 	case ANALOG_SENSOR:
1242 		/* analog */
1243 		printf(" Assertions Enabled    : ");
1244 		for (i = 0; i < 8; i++) {
1245 			if (rsp->data[1] & (1 << i))
1246 				printf("%s ", val2str(1 << i, assert_cond_1));
1247 		}
1248 		if (rsp->data_len > 2) {
1249 			for (i = 0; i < 4; i++) {
1250 				if (rsp->data[2] & (1 << i))
1251 					printf("%s ",
1252 					       val2str(1 << i, assert_cond_2));
1253 			}
1254 			printf("\n");
1255 			if ((rsp->data_len == 4 && rsp->data[3] != 0) ||
1256 			    (rsp->data_len > 4
1257 			     && (rsp->data[3] != 0 || rsp->data[4] != 0))) {
1258 				printf(" Deassertions Enabled  : ");
1259 				for (i = 0; i < 8; i++) {
1260 					if (rsp->data[3] & (1 << i))
1261 						printf("%s ",
1262 						       val2str(1 << i,
1263 							       assert_cond_1));
1264 				}
1265 				if (rsp->data_len > 4) {
1266 					for (i = 0; i < 4; i++) {
1267 						if (rsp->data[4] & (1 << i))
1268 							printf("%s ",
1269 							       val2str(1 << i,
1270 								       assert_cond_2));
1271 					}
1272 				}
1273 				printf("\n");
1274 			}
1275 		} else {
1276 			printf("\n");
1277 		}
1278 		break;
1279 
1280 	default:
1281 		break;
1282 	}
1283 
1284 	return 0;
1285 }
1286 
1287 /* ipmi_sdr_print_sensor_hysteresis  -  print hysteresis for Discrete & Analog
1288  *
1289  * @sensor:		Common Sensor Record SDR pointer
1290  * @full:		Full Sensor Record SDR pointer (if applicable)
1291  * @hysteresis_value:	Actual hysteresis value
1292  * @hvstr:		hysteresis value Identifier String
1293  *
1294  * returns void
1295  */
1296 void
1297 ipmi_sdr_print_sensor_hysteresis(struct sdr_record_common_sensor *sensor,
1298 		 struct sdr_record_full_sensor   *full,
1299 		 uint8_t hysteresis_value,
1300 		 const char *hvstr)
1301 {
1302 	/*
1303 	 * compact can have pos/neg hysteresis, but they cannot be analog!
1304 	 * We use not full in addition to our discrete units check just in
1305 	 * case a compact sensor is incorrectly identified as analog.
1306 	 */
1307 	if (!full || UNITS_ARE_DISCRETE(sensor)) {
1308 		if ( hysteresis_value == 0x00 || hysteresis_value == 0xff ) {
1309 			printf(" %s   : Unspecified\n", hvstr);
1310 		} else {
1311 			printf(" %s   : 0x%02X\n", hvstr, hysteresis_value);
1312 		}
1313 		return;
1314 	}
1315 	/* A Full analog sensor */
1316 	double creading = sdr_convert_sensor_hysterisis(full, hysteresis_value);
1317 	if ( hysteresis_value == 0x00 || hysteresis_value == 0xff ||
1318 	     creading == 0.0 ) {
1319 		printf(" %s   : Unspecified\n", hvstr);
1320 	} else {
1321 		printf(" %s   : %.3f\n", hvstr, creading);
1322 	}
1323 }
1324 
1325 /* print_sensor_min_max  -  print Discrete & Analog Minimum/Maximum Sensor Range
1326  *
1327  * @full:		Full Sensor Record SDR pointer
1328  *
1329  * returns void
1330  */
1331 static void
1332 print_sensor_min_max(struct sdr_record_full_sensor *full)
1333 {
1334 	if (!full) { /* No min/max for compact SDR record */
1335 	    return;
1336 	}
1337 
1338 	double creading = 0.0;
1339 	uint8_t is_analog = !UNITS_ARE_DISCRETE(&full->cmn);
1340 	if (is_analog)
1341 		creading = sdr_convert_sensor_reading(full, full->sensor_min);
1342 	if ((full->cmn.unit.analog == 0 && full->sensor_min == 0x00) ||
1343 	    (full->cmn.unit.analog == 1 && full->sensor_min == 0xff) ||
1344 	    (full->cmn.unit.analog == 2 && full->sensor_min == 0x80) ||
1345 	    (is_analog && (creading == 0.0)))
1346 		printf(" Minimum sensor range  : Unspecified\n");
1347 	else {
1348 		if (is_analog)
1349 			printf(" Minimum sensor range  : %.3f\n", creading);
1350 		else
1351 			printf(" Minimum sensor range  : 0x%02X\n", full->sensor_min);
1352 
1353 	}
1354 	if (is_analog)
1355 		creading = sdr_convert_sensor_reading(full, full->sensor_max);
1356 	if ((full->cmn.unit.analog == 0 && full->sensor_max == 0xff) ||
1357 	    (full->cmn.unit.analog == 1 && full->sensor_max == 0x00) ||
1358 	    (full->cmn.unit.analog == 2 && full->sensor_max == 0x7f) ||
1359 	    (is_analog && (creading == 0.0)))
1360 		printf(" Maximum sensor range  : Unspecified\n");
1361 	else {
1362 		if (is_analog)
1363 			printf(" Maximum sensor range  : %.3f\n", creading);
1364 		else
1365 			printf(" Maximum sensor range  : 0x%02X\n", full->sensor_max);
1366 	}
1367 }
1368 
1369 /* print_csv_discrete  -  print csv formatted discrete sensor
1370  *
1371  * @sensor:		common sensor structure
1372  * @sr:			sensor reading
1373  *
1374  * returns void
1375  */
1376 static void
1377 print_csv_discrete(struct sdr_record_common_sensor    *sensor,
1378 		   const struct sensor_reading *sr)
1379 {
1380 	if (!sr->s_reading_valid  || sr->s_reading_unavailable) {
1381 		printf("%02Xh,ns,%d.%d,No Reading",
1382 		       sensor->keys.sensor_num,
1383 		       sensor->entity.id,
1384 		       sensor->entity.instance);
1385 		return;
1386 	}
1387 
1388 	if (sr->s_has_analog_value) {	/* Sensor has an analog value */
1389 		printf("%s,%s,", sr->s_a_str, sr->s_a_units);
1390 	} else {	/* Sensor has a discrete value */
1391 		printf("%02Xh,", sensor->keys.sensor_num);
1392 	}
1393 	printf("ok,%d.%d,",
1394 	       sensor->entity.id,
1395 	       sensor->entity.instance);
1396 	ipmi_sdr_print_discrete_state_mini(NULL, ", ",
1397 		sensor->sensor.type,
1398 		sensor->event_type,
1399 		sr->s_data2,
1400 		sr->s_data3);
1401 }
1402 
1403 /* ipmi_sdr_read_sensor_value  -  read sensor value
1404  *
1405  * @intf		Interface pointer
1406  * @sensor		Common sensor component pointer
1407  * @sdr_record_type	Type of sdr sensor record
1408  * @precision		decimal precision for analog format conversion
1409  *
1410  * returns a pointer to sensor value reading data structure
1411  */
1412 struct sensor_reading *
1413 ipmi_sdr_read_sensor_value(struct ipmi_intf *intf,
1414 		 struct sdr_record_common_sensor *sensor,
1415 		 uint8_t sdr_record_type, int precision)
1416 {
1417 	static struct sensor_reading sr;
1418 
1419 	if (sensor == NULL)
1420 		return NULL;
1421 
1422 	/* Initialize to reading valid value of zero */
1423 	memset(&sr, 0, sizeof(sr));
1424 
1425 	switch (sdr_record_type) {
1426 		int idlen;
1427 		case (SDR_RECORD_TYPE_FULL_SENSOR):
1428 			sr.full = (struct sdr_record_full_sensor *)sensor;
1429 			idlen = sr.full->id_code & 0x1f;
1430 			idlen = idlen < sizeof(sr.s_id) ?
1431 						idlen : sizeof(sr.s_id) - 1;
1432 			memcpy(sr.s_id, sr.full->id_string, idlen);
1433 			break;
1434 		case SDR_RECORD_TYPE_COMPACT_SENSOR:
1435 			sr.compact = (struct sdr_record_compact_sensor *)sensor;
1436 			idlen = sr.compact->id_code & 0x1f;
1437 			idlen = idlen < sizeof(sr.s_id) ?
1438 						idlen : sizeof(sr.s_id) - 1;
1439 			memcpy(sr.s_id, sr.compact->id_string, idlen);
1440 			break;
1441 		default:
1442 			return NULL;
1443 	}
1444 
1445 	/*
1446 	 * Get current reading via IPMI interface
1447 	 */
1448 	struct ipmi_rs *rsp;
1449 	rsp = ipmi_sdr_get_sensor_reading_ipmb(intf,
1450 					       sensor->keys.sensor_num,
1451 					       sensor->keys.owner_id,
1452 					       sensor->keys.lun,
1453 					       sensor->keys.channel);
1454 	sr.s_a_val   = 0.0;	/* init analog value to a floating point 0 */
1455 	sr.s_a_str[0] = '\0';	/* no converted analog value string */
1456 	sr.s_a_units = "";	/* no converted analog units units */
1457 
1458 
1459 	if (rsp == NULL) {
1460 		lprintf(LOG_DEBUG, "Error reading sensor %s (#%02x)",
1461 			sr.s_id, sensor->keys.sensor_num);
1462 		return &sr;
1463 	}
1464 
1465 	if (rsp->ccode) {
1466 		if ( !((sr.full    && rsp->ccode == 0xcb) ||
1467 		       (sr.compact && rsp->ccode == 0xcd)) ) {
1468 			lprintf(LOG_DEBUG,
1469 				"Error reading sensor %s (#%02x): %s", sr.s_id,
1470 				sensor->keys.sensor_num,
1471 				val2str(rsp->ccode, completion_code_vals));
1472 		}
1473 		return &sr;
1474 	}
1475 
1476 	if (rsp->data_len < 2) {
1477 		/*
1478 		 * We must be returned both a value (data[0]), and the validity
1479 		 * of the value (data[1]), in order to correctly interpret
1480 		 * the reading.    If we don't have both of these we can't have
1481 		 * a valid sensor reading.
1482 		 */
1483 		lprintf(LOG_DEBUG, "Error reading sensor %s invalid len %d",
1484 			sr.s_id, rsp->data_len);
1485 		return &sr;
1486 	}
1487 
1488 
1489 	if (IS_READING_UNAVAILABLE(rsp->data[1]))
1490 		sr.s_reading_unavailable = 1;
1491 
1492 	if (IS_SCANNING_DISABLED(rsp->data[1])) {
1493 		sr.s_scanning_disabled = 1;
1494 		lprintf(LOG_DEBUG, "Sensor %s (#%02x) scanning disabled",
1495 			sr.s_id, sensor->keys.sensor_num);
1496 		return &sr;
1497 	}
1498 	if ( !sr.s_reading_unavailable ) {
1499 		sr.s_reading_valid = 1;
1500 		sr.s_reading = rsp->data[0];
1501 	}
1502 	if (rsp->data_len > 2)
1503 		sr.s_data2   = rsp->data[2];
1504 	if (rsp->data_len > 3)
1505 		sr.s_data3   = rsp->data[3];
1506 	if (sdr_sensor_has_analog_reading(intf, &sr)) {
1507 		sr.s_has_analog_value = 1;
1508 		if (sr.s_reading_valid) {
1509 			sr.s_a_val = sdr_convert_sensor_reading(sr.full, sr.s_reading);
1510 		}
1511 		/* determine units string with possible modifiers */
1512 		sr.s_a_units = ipmi_sdr_get_unit_string(sr.full->cmn.unit.pct,
1513 					   sr.full->cmn.unit.modifier,
1514 					   sr.full->cmn.unit.type.base,
1515 					   sr.full->cmn.unit.type.modifier);
1516 		snprintf(sr.s_a_str, sizeof(sr.s_a_str), "%.*f",
1517 			(sr.s_a_val == (int) sr.s_a_val) ? 0 :
1518 			precision, sr.s_a_val);
1519 	}
1520 	return &sr;
1521 }
1522 
1523 /* ipmi_sdr_print_sensor_fc  -  print full & compact SDR records
1524  *
1525  * @intf:		ipmi interface
1526  * @sensor:		common sensor structure
1527  * @sdr_record_type:	type of sdr record, either full or compact
1528  *
1529  * returns 0 on success
1530  * returns -1 on error
1531  */
1532 int
1533 ipmi_sdr_print_sensor_fc(struct ipmi_intf *intf,
1534 			   struct sdr_record_common_sensor    *sensor,
1535 			   uint8_t sdr_record_type)
1536 {
1537 	char sval[16];
1538 	int i = 0;
1539 	uint8_t target, lun, channel;
1540 	struct sensor_reading *sr;
1541 
1542 
1543 	sr = ipmi_sdr_read_sensor_value(intf, sensor, sdr_record_type, 2);
1544 
1545 	if (sr == NULL)
1546 		return -1;
1547 
1548 	target = sensor->keys.owner_id;
1549 	lun = sensor->keys.lun;
1550 	channel = sensor->keys.channel;
1551 
1552 	/*
1553 	 * CSV OUTPUT
1554 	 */
1555 
1556 	if (csv_output) {
1557 		/*
1558 		 * print sensor name, reading, unit, state
1559 		 */
1560 		printf("%s,", sr->s_id);
1561 		if (!IS_THRESHOLD_SENSOR(sensor)) {
1562 			/* Discrete/Non-Threshold */
1563 			print_csv_discrete(sensor, sr);
1564 			printf("\n");
1565 		}
1566 		else {
1567 			/* Threshold Analog & Discrete*/
1568 			if (sr->s_reading_valid) {
1569 				if (sr->s_has_analog_value) {
1570 					/* Analog/Threshold */
1571 					printf("%.*f,", (sr->s_a_val ==
1572 					(int) sr->s_a_val) ? 0 : 3,
1573 					sr->s_a_val);
1574 					printf("%s,%s", sr->s_a_units,
1575 					       ipmi_sdr_get_thresh_status(sr, "ns"));
1576 				} else { /* Discrete/Threshold */
1577 					print_csv_discrete(sensor, sr);
1578 				}
1579 			} else {
1580 				printf(",,ns");
1581 			}
1582 
1583 			if (verbose) {
1584 				printf(",%d.%d,%s,%s,",
1585 				       sensor->entity.id, sensor->entity.instance,
1586 				       val2str(sensor->entity.id, entity_id_vals),
1587 				       ipmi_sdr_get_sensor_type_desc(sensor->sensor.
1588 								     type));
1589 
1590 				if (sr->full) {
1591 					SENSOR_PRINT_CSV(sr->full, sr->full->analog_flag.nominal_read,
1592 						sr->full->nominal_read);
1593 					SENSOR_PRINT_CSV(sr->full, sr->full->analog_flag.normal_min,
1594 						sr->full->normal_min);
1595 					SENSOR_PRINT_CSV(sr->full, sr->full->analog_flag.normal_max,
1596 						     sr->full->normal_max);
1597 					SENSOR_PRINT_CSV(sr->full, sensor->mask.type.threshold.read.unr,
1598 						sr->full->threshold.upper.non_recover);
1599 					SENSOR_PRINT_CSV(sr->full, sensor->mask.type.threshold.read.ucr,
1600 						sr->full->threshold.upper.critical);
1601 					SENSOR_PRINT_CSV(sr->full, sensor->mask.type.threshold.read.unc,
1602 						sr->full->threshold.upper.non_critical);
1603 					SENSOR_PRINT_CSV(sr->full, sensor->mask.type.threshold.read.lnr,
1604 						sr->full->threshold.lower.non_recover);
1605 					SENSOR_PRINT_CSV(sr->full, sensor->mask.type.threshold.read.lcr,
1606 						sr->full->threshold.lower.critical);
1607 					SENSOR_PRINT_CSV(sr->full, sensor->mask.type.threshold.read.lnc,
1608 						sr->full->threshold.lower.non_critical);
1609 
1610 					if (UNITS_ARE_DISCRETE(sensor)) {
1611 						printf("0x%02X,0x%02X", sr->full->sensor_min, sr->full->sensor_max);
1612 					}
1613 					else {
1614 						printf("%.3f,%.3f",
1615 						       sdr_convert_sensor_reading(sr->full,
1616 									      sr->full->sensor_min),
1617 						       sdr_convert_sensor_reading(sr->full,
1618 									      sr->full->sensor_max));
1619 					}
1620 				} else {
1621 					printf(",,,,,,,,,,");
1622 				}
1623 			}
1624 			printf("\n");
1625 		}
1626 
1627 		return 0;	/* done */
1628 	}
1629 
1630 	/*
1631 	 * NORMAL OUTPUT
1632 	 */
1633 
1634 	if (verbose == 0 && sdr_extended == 0) {
1635 		/*
1636 		 * print sensor name, reading, state
1637 		 */
1638 		printf("%-16s | ", sr->s_id);
1639 
1640 		memset(sval, 0, sizeof (sval));
1641 
1642 		if (sr->s_reading_valid) {
1643 			if( sr->s_has_analog_value ) {
1644 				snprintf(sval, sizeof (sval), "%s %s",
1645 						      sr->s_a_str,
1646 						      sr->s_a_units);
1647 			} else /* Discrete */
1648 				snprintf(sval, sizeof(sval),
1649 					"0x%02x", sr->s_reading);
1650 		}
1651 		else if (sr->s_scanning_disabled)
1652 			snprintf(sval, sizeof (sval), sr->full ? "disabled"   : "Not Readable");
1653 		else
1654 			snprintf(sval, sizeof (sval), sr->full ? "no reading" : "Not Readable");
1655 
1656 		printf("%s", sval);
1657 
1658 		for (i = strlen(sval); i <= sizeof (sval); i++)
1659 			printf(" ");
1660 		printf(" | ");
1661 
1662 		if (IS_THRESHOLD_SENSOR(sensor)) {
1663 			printf("%s", ipmi_sdr_get_thresh_status(sr, "ns"));
1664 		}
1665 		else {
1666 			printf("%s", sr->s_reading_valid ? "ok" : "ns");
1667 		}
1668 
1669 		printf("\n");
1670 
1671 		return 0;	/* done */
1672 	} else if (verbose == 0 && sdr_extended == 1) {
1673 		/*
1674 		 * print sensor name, number, state, entity, reading
1675 		 */
1676 		printf("%-16s | %02Xh | ",
1677 		       sr->s_id, sensor->keys.sensor_num);
1678 
1679 		if (IS_THRESHOLD_SENSOR(sensor)) {
1680 			/* Threshold Analog & Discrete */
1681 			printf("%-3s | %2d.%1d | ",
1682 			   ipmi_sdr_get_thresh_status(sr, "ns"),
1683 		           sensor->entity.id, sensor->entity.instance);
1684 		}
1685 		else {
1686 			/* Non Threshold Analog & Discrete */
1687 			printf("%-3s | %2d.%1d | ",
1688 			       (sr->s_reading_valid ? "ok" : "ns"),
1689 			       sensor->entity.id, sensor->entity.instance);
1690 		}
1691 
1692 		memset(sval, 0, sizeof (sval));
1693 
1694 		if (sr->s_reading_valid) {
1695 			if (IS_THRESHOLD_SENSOR(sensor) &&
1696 				sr->s_has_analog_value ) {
1697 				/* Threshold Analog */
1698 					snprintf(sval, sizeof (sval), "%s %s",
1699 						      sr->s_a_str,
1700 						      sr->s_a_units);
1701 			} else {
1702 				/* Analog & Discrete & Threshold/Discrete */
1703 				char *header = NULL;
1704 				if (sr->s_has_analog_value) { /* Sensor has an analog value */
1705 					printf("%s %s", sr->s_a_str, sr->s_a_units);
1706 					header = ", ";
1707 				}
1708 				ipmi_sdr_print_discrete_state_mini(header, ", ",
1709 								   sensor->sensor.type,
1710 								   sensor->event_type,
1711 								   sr->s_data2,
1712 								   sr->s_data3);
1713 			}
1714 		}
1715 		else if (sr->s_scanning_disabled)
1716 			snprintf(sval, sizeof (sval), "Disabled");
1717 		else
1718 			snprintf(sval, sizeof (sval), "No Reading");
1719 
1720 		printf("%s\n", sval);
1721 		return 0;	/* done */
1722 	}
1723 	/*
1724 	 * VERBOSE OUTPUT
1725 	 */
1726 
1727 	printf("Sensor ID              : %s (0x%x)\n",
1728 	       sr->s_id, sensor->keys.sensor_num);
1729 	printf(" Entity ID             : %d.%d (%s)\n",
1730 	       sensor->entity.id, sensor->entity.instance,
1731 	       val2str(sensor->entity.id, entity_id_vals));
1732 
1733 	if (!IS_THRESHOLD_SENSOR(sensor)) {
1734 		/* Discrete */
1735 		printf(" Sensor Type (Discrete): %s (0x%02x)\n",
1736 				ipmi_sdr_get_sensor_type_desc(sensor->sensor.type),
1737 				sensor->sensor.type);
1738 		lprintf(LOG_DEBUG, " Event Type Code       : 0x%02x",
1739 			sensor->event_type);
1740 
1741 		printf(" Sensor Reading        : ");
1742 		if (sr->s_reading_valid) {
1743 			if (sr->s_has_analog_value) { /* Sensor has an analog value */
1744 				printf("%s %s\n", sr->s_a_str, sr->s_a_units);
1745 			} else {
1746 				printf("%xh\n", sr->s_reading);
1747 			}
1748 		}
1749 		else if (sr->s_scanning_disabled)
1750 			printf("Disabled\n");
1751 		else {
1752 			/* Used to be 'Not Reading' */
1753 			printf("No Reading\n");
1754 		}
1755 
1756 		printf(" Event Message Control : ");
1757 		switch (sensor->sensor.capabilities.event_msg) {
1758 		case 0:
1759 			printf("Per-threshold\n");
1760 			break;
1761 		case 1:
1762 			printf("Entire Sensor Only\n");
1763 			break;
1764 		case 2:
1765 			printf("Global Disable Only\n");
1766 			break;
1767 		case 3:
1768 			printf("No Events From Sensor\n");
1769 			break;
1770 		}
1771 
1772 		ipmi_sdr_print_discrete_state("States Asserted",
1773 					      sensor->sensor.type,
1774 					      sensor->event_type,
1775 					      sr->s_data2,
1776 					      sr->s_data3);
1777 		ipmi_sdr_print_sensor_mask(&sensor->mask, sensor->sensor.type,
1778 					   sensor->event_type, DISCRETE_SENSOR);
1779 		ipmi_sdr_print_sensor_event_status(intf,
1780 						   sensor->keys.sensor_num,
1781 						   sensor->sensor.type,
1782 						   sensor->event_type,
1783 						   DISCRETE_SENSOR,
1784 						   target,
1785 						   lun, channel);
1786 		ipmi_sdr_print_sensor_event_enable(intf,
1787 						   sensor->keys.sensor_num,
1788 						   sensor->sensor.type,
1789 						   sensor->event_type,
1790 						   DISCRETE_SENSOR,
1791 						   target,
1792 						   lun, channel);
1793 		printf(" OEM                   : %X\n",
1794 					sr->full ? sr->full->oem : sr->compact->oem);
1795 		printf("\n");
1796 
1797 		return 0;	/* done */
1798 	}
1799 	printf(" Sensor Type (Threshold)  : %s (0x%02x)\n",
1800 		ipmi_sdr_get_sensor_type_desc(sensor->sensor.type),
1801 		sensor->sensor.type);
1802 
1803 	printf(" Sensor Reading        : ");
1804 	if (sr->s_reading_valid) {
1805 		if (sr->full) {
1806 			uint16_t raw_tol = __TO_TOL(sr->full->mtol);
1807 			if (UNITS_ARE_DISCRETE(sensor)) {
1808 				printf("0x%02X (+/- 0x%02X) %s\n",
1809 				sr->s_reading, raw_tol, sr->s_a_units);
1810 			}
1811 			else {
1812 				double tol = sdr_convert_sensor_tolerance(sr->full, raw_tol);
1813 				printf("%.*f (+/- %.*f) %s\n",
1814 				       (sr->s_a_val == (int) sr->s_a_val) ? 0 : 3,
1815 				       sr->s_a_val, (tol == (int) tol) ? 0 :
1816 				       3, tol, sr->s_a_units);
1817 			}
1818 		} else {
1819 			printf("0x%02X %s\n", sr->s_reading, sr->s_a_units);
1820 		}
1821 	} else if (sr->s_scanning_disabled)
1822 		printf("Disabled\n");
1823 	else
1824 		printf("No Reading\n");
1825 
1826 	printf(" Status                : %s\n",
1827 	       ipmi_sdr_get_thresh_status(sr, "Not Available"));
1828 
1829 	if(sr->full) {
1830 		SENSOR_PRINT_NORMAL(sr->full, "Nominal Reading", nominal_read);
1831 		SENSOR_PRINT_NORMAL(sr->full, "Normal Minimum", normal_min);
1832 		SENSOR_PRINT_NORMAL(sr->full, "Normal Maximum", normal_max);
1833 
1834 		SENSOR_PRINT_THRESH(sr->full, "Upper non-recoverable", upper.non_recover, unr);
1835 		SENSOR_PRINT_THRESH(sr->full, "Upper critical", upper.critical, ucr);
1836 		SENSOR_PRINT_THRESH(sr->full, "Upper non-critical", upper.non_critical, unc);
1837 		SENSOR_PRINT_THRESH(sr->full, "Lower non-recoverable", lower.non_recover, lnr);
1838 		SENSOR_PRINT_THRESH(sr->full, "Lower critical", lower.critical, lcr);
1839 		SENSOR_PRINT_THRESH(sr->full, "Lower non-critical", lower.non_critical, lnc);
1840 	}
1841 	ipmi_sdr_print_sensor_hysteresis(sensor, sr->full,
1842 		sr->full ? sr->full->threshold.hysteresis.positive :
1843 		sr->compact->threshold.hysteresis.positive, "Positive Hysteresis");
1844 
1845 	ipmi_sdr_print_sensor_hysteresis(sensor, sr->full,
1846 		sr->full ? sr->full->threshold.hysteresis.negative :
1847 		sr->compact->threshold.hysteresis.negative, "Negative Hysteresis");
1848 
1849 	print_sensor_min_max(sr->full);
1850 
1851 	printf(" Event Message Control : ");
1852 	switch (sensor->sensor.capabilities.event_msg) {
1853 	case 0:
1854 		printf("Per-threshold\n");
1855 		break;
1856 	case 1:
1857 		printf("Entire Sensor Only\n");
1858 		break;
1859 	case 2:
1860 		printf("Global Disable Only\n");
1861 		break;
1862 	case 3:
1863 		printf("No Events From Sensor\n");
1864 		break;
1865 	}
1866 
1867 	printf(" Readable Thresholds   : ");
1868 	switch (sensor->sensor.capabilities.threshold) {
1869 	case 0:
1870 		printf("No Thresholds\n");
1871 		break;
1872 	case 1:		/* readable according to mask */
1873 	case 2:		/* readable and settable according to mask */
1874 		if (sensor->mask.type.threshold.read.lnr)
1875 			printf("lnr ");
1876 		if (sensor->mask.type.threshold.read.lcr)
1877 			printf("lcr ");
1878 		if (sensor->mask.type.threshold.read.lnc)
1879 			printf("lnc ");
1880 		if (sensor->mask.type.threshold.read.unc)
1881 			printf("unc ");
1882 		if (sensor->mask.type.threshold.read.ucr)
1883 			printf("ucr ");
1884 		if (sensor->mask.type.threshold.read.unr)
1885 			printf("unr ");
1886 		printf("\n");
1887 		break;
1888 	case 3:
1889 		printf("Thresholds Fixed\n");
1890 		break;
1891 	}
1892 
1893 	printf(" Settable Thresholds   : ");
1894 	switch (sensor->sensor.capabilities.threshold) {
1895 	case 0:
1896 		printf("No Thresholds\n");
1897 		break;
1898 	case 1:		/* readable according to mask */
1899 	case 2:		/* readable and settable according to mask */
1900 		if (sensor->mask.type.threshold.set.lnr)
1901 			printf("lnr ");
1902 		if (sensor->mask.type.threshold.set.lcr)
1903 			printf("lcr ");
1904 		if (sensor->mask.type.threshold.set.lnc)
1905 			printf("lnc ");
1906 		if (sensor->mask.type.threshold.set.unc)
1907 			printf("unc ");
1908 		if (sensor->mask.type.threshold.set.ucr)
1909 			printf("ucr ");
1910 		if (sensor->mask.type.threshold.set.unr)
1911 			printf("unr ");
1912 		printf("\n");
1913 		break;
1914 	case 3:
1915 		printf("Thresholds Fixed\n");
1916 		break;
1917 	}
1918 
1919 	if (sensor->mask.type.threshold.status_lnr ||
1920 	    sensor->mask.type.threshold.status_lcr ||
1921 	    sensor->mask.type.threshold.status_lnc ||
1922 	    sensor->mask.type.threshold.status_unc ||
1923 	    sensor->mask.type.threshold.status_ucr ||
1924 	    sensor->mask.type.threshold.status_unr) {
1925 		printf(" Threshold Read Mask   : ");
1926 		if (sensor->mask.type.threshold.status_lnr)
1927 			printf("lnr ");
1928 		if (sensor->mask.type.threshold.status_lcr)
1929 			printf("lcr ");
1930 		if (sensor->mask.type.threshold.status_lnc)
1931 			printf("lnc ");
1932 		if (sensor->mask.type.threshold.status_unc)
1933 			printf("unc ");
1934 		if (sensor->mask.type.threshold.status_ucr)
1935 			printf("ucr ");
1936 		if (sensor->mask.type.threshold.status_unr)
1937 			printf("unr ");
1938 		printf("\n");
1939 	}
1940 
1941 	ipmi_sdr_print_sensor_mask(&sensor->mask,
1942 				   sensor->sensor.type,
1943 				   sensor->event_type, ANALOG_SENSOR);
1944 	ipmi_sdr_print_sensor_event_status(intf,
1945 					   sensor->keys.sensor_num,
1946 					   sensor->sensor.type,
1947 					   sensor->event_type, ANALOG_SENSOR,
1948 					   target,
1949 					   lun, channel);
1950 
1951 	ipmi_sdr_print_sensor_event_enable(intf,
1952 					   sensor->keys.sensor_num,
1953 					   sensor->sensor.type,
1954 					   sensor->event_type, ANALOG_SENSOR,
1955 					   target,
1956 					   lun, channel);
1957 
1958 	printf("\n");
1959 	return 0;
1960 }
1961 
1962 static inline int
1963 get_offset(uint8_t x)
1964 {
1965 	int i;
1966 	for (i = 0; i < 8; i++)
1967 		if (x >> i == 1)
1968 			return i;
1969 	return 0;
1970 }
1971 
1972 /* ipmi_sdr_print_discrete_state_mini  -  print list of asserted states
1973  *                                        for a discrete sensor
1974  *
1975  * @header	: header string if necessary
1976  * @separator	: field separator string
1977  * @sensor_type	: sensor type code
1978  * @event_type	: event type code
1979  * @state	: mask of asserted states
1980  *
1981  * no meaningful return value
1982  */
1983 void
1984 ipmi_sdr_print_discrete_state_mini(const char *header, const char *separator,
1985 				   uint8_t sensor_type, uint8_t event_type,
1986 				   uint8_t state1, uint8_t state2)
1987 {
1988 	uint8_t typ;
1989 	struct ipmi_event_sensor_types *evt;
1990 	int pre = 0, c = 0;
1991 
1992 	if (state1 == 0 && (state2 & 0x7f) == 0)
1993 		return;
1994 
1995 	if (event_type == 0x6f) {
1996 		evt = sensor_specific_types;
1997 		typ = sensor_type;
1998 	} else {
1999 		evt = generic_event_types;
2000 		typ = event_type;
2001 	}
2002 
2003 	if (header)
2004 		printf("%s", header);
2005 
2006 	for (; evt->type != NULL; evt++) {
2007 		if ((evt->code != typ) ||
2008 			(evt->data != 0xFF))
2009 			continue;
2010 
2011 		if (evt->offset > 7) {
2012 			if ((1 << (evt->offset - 8)) & (state2 & 0x7f)) {
2013 				if (pre++ != 0)
2014 					printf("%s", separator);
2015 				if (evt->desc)
2016 					printf("%s", evt->desc);
2017 			}
2018 		} else {
2019 			if ((1 << evt->offset) & state1) {
2020 				if (pre++ != 0)
2021 					printf("%s", separator);
2022 				if (evt->desc)
2023 					printf("%s", evt->desc);
2024 			}
2025 		}
2026 		c++;
2027 	}
2028 }
2029 
2030 /* ipmi_sdr_print_discrete_state  -  print list of asserted states
2031  *                                   for a discrete sensor
2032  *
2033  * @desc        : description for this line
2034  * @sensor_type	: sensor type code
2035  * @event_type	: event type code
2036  * @state	: mask of asserted states
2037  *
2038  * no meaningful return value
2039  */
2040 void
2041 ipmi_sdr_print_discrete_state(const char *desc,
2042 			      uint8_t sensor_type, uint8_t event_type,
2043 			      uint8_t state1, uint8_t state2)
2044 {
2045 	uint8_t typ;
2046 	struct ipmi_event_sensor_types *evt;
2047 	int pre = 0, c = 0;
2048 
2049 	if (state1 == 0 && (state2 & 0x7f) == 0)
2050 		return;
2051 
2052 	if (event_type == 0x6f) {
2053 		evt = sensor_specific_types;
2054 		typ = sensor_type;
2055 	} else {
2056 		evt = generic_event_types;
2057 		typ = event_type;
2058 	}
2059 
2060 	for (; evt->type != NULL; evt++) {
2061 		if ((evt->code != typ) ||
2062 			(evt->data != 0xFF))
2063 			continue;
2064 
2065 		if (pre == 0) {
2066 			printf(" %-21s : %s\n", desc, evt->type);
2067 			pre = 1;
2068 		}
2069 
2070 		if (evt->offset > 7) {
2071 			if ((1 << (evt->offset - 8)) & (state2 & 0x7f)) {
2072 				if (evt->desc) {
2073 					printf("                         "
2074 					       "[%s]\n",
2075 					       evt->desc);
2076 				} else {
2077 					printf("                         "
2078 					       "[no description]\n");
2079 				}
2080 			}
2081 		} else {
2082 			if ((1 << evt->offset) & state1) {
2083 				if (evt->desc) {
2084 					printf("                         "
2085 					       "[%s]\n",
2086 					       evt->desc);
2087 				} else {
2088 					printf("                         "
2089 					       "[no description]\n");
2090 				}
2091 			}
2092 		}
2093 		c++;
2094 	}
2095 }
2096 
2097 
2098 /* ipmi_sdr_print_sensor_eventonly  -  print SDR event only record
2099  *
2100  * @intf:	ipmi interface
2101  * @sensor:	event only sdr record
2102  *
2103  * returns 0 on success
2104  * returns -1 on error
2105  */
2106 int
2107 ipmi_sdr_print_sensor_eventonly(struct ipmi_intf *intf,
2108 				struct sdr_record_eventonly_sensor *sensor)
2109 {
2110 	char desc[17];
2111 
2112 	if (sensor == NULL)
2113 		return -1;
2114 
2115 	memset(desc, 0, sizeof (desc));
2116 	snprintf(desc, (sensor->id_code & 0x1f) + 1, "%s", sensor->id_string);
2117 
2118 	if (verbose) {
2119 		printf("Sensor ID              : %s (0x%x)\n",
2120 		       sensor->id_code ? desc : "", sensor->keys.sensor_num);
2121 		printf("Entity ID              : %d.%d (%s)\n",
2122 		       sensor->entity.id, sensor->entity.instance,
2123 		       val2str(sensor->entity.id, entity_id_vals));
2124 		printf("Sensor Type            : %s (0x%02x)\n",
2125 			ipmi_sdr_get_sensor_type_desc(sensor->sensor_type),
2126 			sensor->sensor_type);
2127 		lprintf(LOG_DEBUG, "Event Type Code        : 0x%02x",
2128 			sensor->event_type);
2129 		printf("\n");
2130 	} else {
2131 		if (csv_output)
2132 			printf("%s,%02Xh,ns,%d.%d,Event-Only\n",
2133 			       sensor->id_code ? desc : "",
2134 			       sensor->keys.sensor_num,
2135 			       sensor->entity.id, sensor->entity.instance);
2136 		else if (sdr_extended)
2137 			printf("%-16s | %02Xh | ns  | %2d.%1d | Event-Only\n",
2138 			       sensor->id_code ? desc : "",
2139 			       sensor->keys.sensor_num,
2140 			       sensor->entity.id, sensor->entity.instance);
2141 		else
2142 			printf("%-16s | Event-Only        | ns\n",
2143 			       sensor->id_code ? desc : "");
2144 	}
2145 
2146 	return 0;
2147 }
2148 
2149 /* ipmi_sdr_print_sensor_mc_locator  -  print SDR MC locator record
2150  *
2151  * @intf:	ipmi interface
2152  * @mc:		mc locator sdr record
2153  *
2154  * returns 0 on success
2155  * returns -1 on error
2156  */
2157 int
2158 ipmi_sdr_print_sensor_mc_locator(struct ipmi_intf *intf,
2159 				 struct sdr_record_mc_locator *mc)
2160 {
2161 	char desc[17];
2162 
2163 	if (mc == NULL)
2164 		return -1;
2165 
2166 	memset(desc, 0, sizeof (desc));
2167 	snprintf(desc, (mc->id_code & 0x1f) + 1, "%s", mc->id_string);
2168 
2169 	if (verbose == 0) {
2170 		if (csv_output)
2171 			printf("%s,00h,ok,%d.%d\n",
2172 			       mc->id_code ? desc : "",
2173 			       mc->entity.id, mc->entity.instance);
2174 		else if (sdr_extended) {
2175 			printf("%-16s | 00h | ok  | %2d.%1d | ",
2176 			       mc->id_code ? desc : "",
2177 			       mc->entity.id, mc->entity.instance);
2178 
2179 			printf("%s MC @ %02Xh\n",
2180 			       (mc->
2181 				pwr_state_notif & 0x1) ? "Static" : "Dynamic",
2182 			       mc->dev_slave_addr);
2183 		} else {
2184 			printf("%-16s | %s MC @ %02Xh %s | ok\n",
2185 			       mc->id_code ? desc : "",
2186 			       (mc->
2187 				pwr_state_notif & 0x1) ? "Static" : "Dynamic",
2188 			       mc->dev_slave_addr,
2189 			       (mc->pwr_state_notif & 0x1) ? " " : "");
2190 		}
2191 
2192 		return 0;	/* done */
2193 	}
2194 
2195 	printf("Device ID              : %s\n", mc->id_string);
2196 	printf("Entity ID              : %d.%d (%s)\n",
2197 	       mc->entity.id, mc->entity.instance,
2198 	       val2str(mc->entity.id, entity_id_vals));
2199 
2200 	printf("Device Slave Address   : %02Xh\n", mc->dev_slave_addr);
2201 	printf("Channel Number         : %01Xh\n", mc->channel_num);
2202 
2203 	printf("ACPI System P/S Notif  : %sRequired\n",
2204 	       (mc->pwr_state_notif & 0x4) ? "" : "Not ");
2205 	printf("ACPI Device P/S Notif  : %sRequired\n",
2206 	       (mc->pwr_state_notif & 0x2) ? "" : "Not ");
2207 	printf("Controller Presence    : %s\n",
2208 	       (mc->pwr_state_notif & 0x1) ? "Static" : "Dynamic");
2209 	printf("Logs Init Agent Errors : %s\n",
2210 	       (mc->global_init & 0x8) ? "Yes" : "No");
2211 
2212 	printf("Event Message Gen      : ");
2213 	if (!(mc->global_init & 0x3))
2214 		printf("Enable\n");
2215 	else if ((mc->global_init & 0x3) == 0x1)
2216 		printf("Disable\n");
2217 	else if ((mc->global_init & 0x3) == 0x2)
2218 		printf("Do Not Init Controller\n");
2219 	else
2220 		printf("Reserved\n");
2221 
2222 	printf("Device Capabilities\n");
2223 	printf(" Chassis Device        : %s\n",
2224 	       (mc->dev_support & 0x80) ? "Yes" : "No");
2225 	printf(" Bridge                : %s\n",
2226 	       (mc->dev_support & 0x40) ? "Yes" : "No");
2227 	printf(" IPMB Event Generator  : %s\n",
2228 	       (mc->dev_support & 0x20) ? "Yes" : "No");
2229 	printf(" IPMB Event Receiver   : %s\n",
2230 	       (mc->dev_support & 0x10) ? "Yes" : "No");
2231 	printf(" FRU Inventory Device  : %s\n",
2232 	       (mc->dev_support & 0x08) ? "Yes" : "No");
2233 	printf(" SEL Device            : %s\n",
2234 	       (mc->dev_support & 0x04) ? "Yes" : "No");
2235 	printf(" SDR Repository        : %s\n",
2236 	       (mc->dev_support & 0x02) ? "Yes" : "No");
2237 	printf(" Sensor Device         : %s\n",
2238 	       (mc->dev_support & 0x01) ? "Yes" : "No");
2239 
2240 	printf("\n");
2241 
2242 	return 0;
2243 }
2244 
2245 /* ipmi_sdr_print_sensor_generic_locator  -  print generic device locator record
2246  *
2247  * @intf:	ipmi interface
2248  * @gen:	generic device locator sdr record
2249  *
2250  * returns 0 on success
2251  * returns -1 on error
2252  */
2253 int
2254 ipmi_sdr_print_sensor_generic_locator(struct ipmi_intf *intf,
2255 				      struct sdr_record_generic_locator *dev)
2256 {
2257 	char desc[17];
2258 
2259 	memset(desc, 0, sizeof (desc));
2260 	snprintf(desc, (dev->id_code & 0x1f) + 1, "%s", dev->id_string);
2261 
2262 	if (!verbose) {
2263 		if (csv_output)
2264 			printf("%s,00h,ns,%d.%d\n",
2265 			       dev->id_code ? desc : "",
2266 			       dev->entity.id, dev->entity.instance);
2267 		else if (sdr_extended)
2268 			printf
2269 			    ("%-16s | 00h | ns  | %2d.%1d | Generic Device @%02Xh:%02Xh.%1d\n",
2270 			     dev->id_code ? desc : "", dev->entity.id,
2271 			     dev->entity.instance, dev->dev_access_addr,
2272 			     dev->dev_slave_addr, dev->oem);
2273 		else
2274 			printf("%-16s | Generic @%02X:%02X.%-2d | ok\n",
2275 			       dev->id_code ? desc : "",
2276 			       dev->dev_access_addr,
2277 			       dev->dev_slave_addr, dev->oem);
2278 
2279 		return 0;
2280 	}
2281 
2282 	printf("Device ID              : %s\n", dev->id_string);
2283 	printf("Entity ID              : %d.%d (%s)\n",
2284 	       dev->entity.id, dev->entity.instance,
2285 	       val2str(dev->entity.id, entity_id_vals));
2286 
2287 	printf("Device Access Address  : %02Xh\n", dev->dev_access_addr);
2288 	printf("Device Slave Address   : %02Xh\n", dev->dev_slave_addr);
2289 	printf("Address Span           : %02Xh\n", dev->addr_span);
2290 	printf("Channel Number         : %01Xh\n", dev->channel_num);
2291 	printf("LUN.Bus                : %01Xh.%01Xh\n", dev->lun, dev->bus);
2292 	printf("Device Type.Modifier   : %01Xh.%01Xh (%s)\n",
2293 	       dev->dev_type, dev->dev_type_modifier,
2294 	       val2str(dev->dev_type << 8 | dev->dev_type_modifier,
2295 		       entity_device_type_vals));
2296 	printf("OEM                    : %02Xh\n", dev->oem);
2297 	printf("\n");
2298 
2299 	return 0;
2300 }
2301 
2302 /* ipmi_sdr_print_sensor_fru_locator  -  print FRU locator record
2303  *
2304  * @intf:	ipmi interface
2305  * @fru:	fru locator sdr record
2306  *
2307  * returns 0 on success
2308  * returns -1 on error
2309  */
2310 int
2311 ipmi_sdr_print_sensor_fru_locator(struct ipmi_intf *intf,
2312 				  struct sdr_record_fru_locator *fru)
2313 {
2314 	char desc[17];
2315 
2316 	memset(desc, 0, sizeof (desc));
2317 	snprintf(desc, (fru->id_code & 0x1f) + 1, "%s", fru->id_string);
2318 
2319 	if (!verbose) {
2320 		if (csv_output)
2321 			printf("%s,00h,ns,%d.%d\n",
2322 			       fru->id_code ? desc : "",
2323 			       fru->entity.id, fru->entity.instance);
2324 		else if (sdr_extended)
2325 			printf("%-16s | 00h | ns  | %2d.%1d | %s FRU @%02Xh\n",
2326 			       fru->id_code ? desc : "",
2327 			       fru->entity.id, fru->entity.instance,
2328 			       (fru->logical) ? "Logical" : "Physical",
2329 			       fru->device_id);
2330 		else
2331 			printf("%-16s | %s FRU @%02Xh %02x.%x | ok\n",
2332 			       fru->id_code ? desc : "",
2333 			       (fru->logical) ? "Log" : "Phy",
2334 			       fru->device_id,
2335 			       fru->entity.id, fru->entity.instance);
2336 
2337 		return 0;
2338 	}
2339 
2340 	printf("Device ID              : %s\n", fru->id_string);
2341 	printf("Entity ID              : %d.%d (%s)\n",
2342 	       fru->entity.id, fru->entity.instance,
2343 	       val2str(fru->entity.id, entity_id_vals));
2344 
2345 	printf("Device Access Address  : %02Xh\n", fru->dev_slave_addr);
2346 	printf("%s: %02Xh\n",
2347 	       fru->logical ? "Logical FRU Device     " :
2348 	       "Slave Address          ", fru->device_id);
2349 	printf("Channel Number         : %01Xh\n", fru->channel_num);
2350 	printf("LUN.Bus                : %01Xh.%01Xh\n", fru->lun, fru->bus);
2351 	printf("Device Type.Modifier   : %01Xh.%01Xh (%s)\n",
2352 	       fru->dev_type, fru->dev_type_modifier,
2353 	       val2str(fru->dev_type << 8 | fru->dev_type_modifier,
2354 		       entity_device_type_vals));
2355 	printf("OEM                    : %02Xh\n", fru->oem);
2356 	printf("\n");
2357 
2358 	return 0;
2359 }
2360 
2361 /* ipmi_sdr_print_sensor_entity_assoc  -  print SDR entity association record
2362  *
2363  * @intf:	ipmi interface
2364  * @mc:		entity association sdr record
2365  *
2366  * returns 0 on success
2367  * returns -1 on error
2368  */
2369 int
2370 ipmi_sdr_print_sensor_entity_assoc(struct ipmi_intf *intf,
2371 				   struct sdr_record_entity_assoc *assoc)
2372 {
2373 	return 0;
2374 }
2375 
2376 /* ipmi_sdr_print_sensor_oem_intel  -  print Intel OEM sensors
2377  *
2378  * @intf:	ipmi interface
2379  * @oem:	oem sdr record
2380  *
2381  * returns 0 on success
2382  * returns -1 on error
2383  */
2384 static int
2385 ipmi_sdr_print_sensor_oem_intel(struct ipmi_intf *intf,
2386 				struct sdr_record_oem *oem)
2387 {
2388 	switch (oem->data[3]) {	/* record sub-type */
2389 	case 0x02:		/* Power Unit Map */
2390 		if (verbose) {
2391 			printf
2392 			    ("Sensor ID              : Power Unit Redundancy (0x%x)\n",
2393 			     oem->data[4]);
2394 			printf
2395 			    ("Sensor Type            : Intel OEM - Power Unit Map\n");
2396 			printf("Redundant Supplies     : %d", oem->data[6]);
2397 			if (oem->data[5])
2398 				printf(" (flags %xh)", oem->data[5]);
2399 			printf("\n");
2400 		}
2401 
2402 		switch (oem->data_len) {
2403 		case 7:	/* SR1300, non-redundant */
2404 			if (verbose)
2405 				printf("Power Redundancy       : No\n");
2406 			else if (csv_output)
2407 				printf("Power Redundancy,Not Available,nr\n");
2408 			else
2409 				printf
2410 				    ("Power Redundancy | Not Available     | nr\n");
2411 			break;
2412 		case 8:	/* SR2300, redundant, PS1 & PS2 present */
2413 			if (verbose) {
2414 				printf("Power Redundancy       : No\n");
2415 				printf("Power Supply 2 Sensor  : %x\n",
2416 				       oem->data[8]);
2417 			} else if (csv_output) {
2418 				printf("Power Redundancy,PS@%02xh,nr\n",
2419 				       oem->data[8]);
2420 			} else {
2421 				printf
2422 				    ("Power Redundancy | PS@%02xh            | nr\n",
2423 				     oem->data[8]);
2424 			}
2425 			break;
2426 		case 9:	/* SR2300, non-redundant, PSx present */
2427 			if (verbose) {
2428 				printf("Power Redundancy       : Yes\n");
2429 				printf("Power Supply Sensor    : %x\n",
2430 				       oem->data[7]);
2431 				printf("Power Supply Sensor    : %x\n",
2432 				       oem->data[8]);
2433 			} else if (csv_output) {
2434 				printf
2435 				    ("Power Redundancy,PS@%02xh + PS@%02xh,ok\n",
2436 				     oem->data[7], oem->data[8]);
2437 			} else {
2438 				printf
2439 				    ("Power Redundancy | PS@%02xh + PS@%02xh   | ok\n",
2440 				     oem->data[7], oem->data[8]);
2441 			}
2442 			break;
2443 		}
2444 		if (verbose)
2445 			printf("\n");
2446 		break;
2447 	case 0x03:		/* Fan Speed Control */
2448 		break;
2449 	case 0x06:		/* System Information */
2450 		break;
2451 	case 0x07:		/* Ambient Temperature Fan Speed Control */
2452 		break;
2453 	default:
2454 		lprintf(LOG_DEBUG, "Unknown Intel OEM SDR Record type %02x",
2455 			oem->data[3]);
2456 	}
2457 
2458 	return 0;
2459 }
2460 
2461 /* ipmi_sdr_print_sensor_oem  -  print OEM sensors
2462  *
2463  * This function is generally only filled out by decoding what
2464  * a particular BMC might stuff into its OEM records.  The
2465  * records are keyed off manufacturer ID and record subtypes.
2466  *
2467  * @intf:	ipmi interface
2468  * @oem:	oem sdr record
2469  *
2470  * returns 0 on success
2471  * returns -1 on error
2472  */
2473 static int
2474 ipmi_sdr_print_sensor_oem(struct ipmi_intf *intf, struct sdr_record_oem *oem)
2475 {
2476 	int rc = 0;
2477 
2478 	if (oem == NULL)
2479 		return -1;
2480 	if (oem->data_len == 0 || oem->data == NULL)
2481 		return -1;
2482 
2483 	if (verbose > 2)
2484 		printbuf(oem->data, oem->data_len, "OEM Record");
2485 
2486 	/* intel manufacturer id */
2487 	if (oem->data[0] == 0x57 &&
2488 	    oem->data[1] == 0x01 && oem->data[2] == 0x00) {
2489 		rc = ipmi_sdr_print_sensor_oem_intel(intf, oem);
2490 	}
2491 
2492 	return rc;
2493 }
2494 
2495 /* ipmi_sdr_print_name_from_rawentry  -  Print SDR name  from raw data
2496  *
2497  * @intf:	ipmi interface
2498  * @type:	sensor type
2499  * @raw:	raw sensor data
2500  *
2501  * returns 0 on success
2502  * returns -1 on error
2503  */
2504 int
2505 ipmi_sdr_print_name_from_rawentry(struct ipmi_intf *intf,uint16_t id,
2506                                   uint8_t type,uint8_t * raw)
2507 {
2508    union {
2509       struct sdr_record_full_sensor *full;
2510       struct sdr_record_compact_sensor *compact;
2511       struct sdr_record_eventonly_sensor *eventonly;
2512       struct sdr_record_generic_locator *genloc;
2513       struct sdr_record_fru_locator *fruloc;
2514       struct sdr_record_mc_locator *mcloc;
2515       struct sdr_record_entity_assoc *entassoc;
2516       struct sdr_record_oem *oem;
2517    } record;
2518 
2519    int rc =0;
2520    char desc[17];
2521    memset(desc, ' ', sizeof (desc));
2522 
2523    switch ( type) {
2524       case SDR_RECORD_TYPE_FULL_SENSOR:
2525       record.full = (struct sdr_record_full_sensor *) raw;
2526       snprintf(desc, (record.full->id_code & 0x1f) +1, "%s",
2527                (const char *)record.full->id_string);
2528       break;
2529       case SDR_RECORD_TYPE_COMPACT_SENSOR:
2530       record.compact = (struct sdr_record_compact_sensor *) raw	;
2531       snprintf(desc, (record.compact->id_code & 0x1f)  +1, "%s",
2532                (const char *)record.compact->id_string);
2533       break;
2534       case SDR_RECORD_TYPE_EVENTONLY_SENSOR:
2535       record.eventonly  = (struct sdr_record_eventonly_sensor *) raw ;
2536       snprintf(desc, (record.eventonly->id_code & 0x1f)  +1, "%s",
2537                (const char *)record.eventonly->id_string);
2538       break;
2539       case SDR_RECORD_TYPE_MC_DEVICE_LOCATOR:
2540       record.mcloc  = (struct sdr_record_mc_locator *) raw ;
2541       snprintf(desc, (record.mcloc->id_code & 0x1f)  +1, "%s",
2542                (const char *)record.mcloc->id_string);
2543       break;
2544       default:
2545       rc = -1;
2546       break;
2547    }
2548 
2549       lprintf(LOG_INFO, "ID: 0x%04x , NAME: %-16s", id, desc);
2550    return rc;
2551 }
2552 
2553 /* ipmi_sdr_print_rawentry  -  Print SDR entry from raw data
2554  *
2555  * @intf:	ipmi interface
2556  * @type:	sensor type
2557  * @raw:	raw sensor data
2558  * @len:	length of raw sensor data
2559  *
2560  * returns 0 on success
2561  * returns -1 on error
2562  */
2563 int
2564 ipmi_sdr_print_rawentry(struct ipmi_intf *intf, uint8_t type,
2565 			uint8_t * raw, int len)
2566 {
2567 	int rc = 0;
2568 
2569 	switch (type) {
2570 	case SDR_RECORD_TYPE_FULL_SENSOR:
2571 	case SDR_RECORD_TYPE_COMPACT_SENSOR:
2572 		rc = ipmi_sdr_print_sensor_fc(intf,
2573 					(struct sdr_record_common_sensor *) raw,
2574 					type);
2575 		break;
2576 	case SDR_RECORD_TYPE_EVENTONLY_SENSOR:
2577 		rc = ipmi_sdr_print_sensor_eventonly(intf,
2578 						     (struct
2579 						      sdr_record_eventonly_sensor
2580 						      *) raw);
2581 		break;
2582 	case SDR_RECORD_TYPE_GENERIC_DEVICE_LOCATOR:
2583 		rc = ipmi_sdr_print_sensor_generic_locator(intf,
2584 							   (struct
2585 							    sdr_record_generic_locator
2586 							    *) raw);
2587 		break;
2588 	case SDR_RECORD_TYPE_FRU_DEVICE_LOCATOR:
2589 		rc = ipmi_sdr_print_sensor_fru_locator(intf,
2590 						       (struct
2591 							sdr_record_fru_locator
2592 							*) raw);
2593 		break;
2594 	case SDR_RECORD_TYPE_MC_DEVICE_LOCATOR:
2595 		rc = ipmi_sdr_print_sensor_mc_locator(intf,
2596 						      (struct
2597 						       sdr_record_mc_locator *)
2598 						      raw);
2599 		break;
2600 	case SDR_RECORD_TYPE_ENTITY_ASSOC:
2601 		rc = ipmi_sdr_print_sensor_entity_assoc(intf,
2602 							(struct
2603 							 sdr_record_entity_assoc
2604 							 *) raw);
2605 		break;
2606 	case SDR_RECORD_TYPE_OEM:{
2607 			struct sdr_record_oem oem;
2608 			oem.data = raw;
2609 			oem.data_len = len;
2610 			rc = ipmi_sdr_print_sensor_oem(intf,
2611 						       (struct sdr_record_oem *)
2612 						       &oem);
2613 			break;
2614 		}
2615 	case SDR_RECORD_TYPE_DEVICE_ENTITY_ASSOC:
2616 	case SDR_RECORD_TYPE_MC_CONFIRMATION:
2617 	case SDR_RECORD_TYPE_BMC_MSG_CHANNEL_INFO:
2618 		/* not implemented */
2619 		break;
2620 	}
2621 
2622 	return rc;
2623 }
2624 
2625 /* ipmi_sdr_print_listentry  -  Print SDR entry from list
2626  *
2627  * @intf:	ipmi interface
2628  * @entry:	sdr record list entry
2629  *
2630  * returns 0 on success
2631  * returns -1 on error
2632  */
2633 int
2634 ipmi_sdr_print_listentry(struct ipmi_intf *intf, struct sdr_record_list *entry)
2635 {
2636 	int rc = 0;
2637 
2638 	switch (entry->type) {
2639 	case SDR_RECORD_TYPE_FULL_SENSOR:
2640 	case SDR_RECORD_TYPE_COMPACT_SENSOR:
2641 		rc = ipmi_sdr_print_sensor_fc(intf, entry->record.common, entry->type);
2642 		break;
2643 	case SDR_RECORD_TYPE_EVENTONLY_SENSOR:
2644 		rc = ipmi_sdr_print_sensor_eventonly(intf,
2645 						     entry->record.eventonly);
2646 		break;
2647 	case SDR_RECORD_TYPE_GENERIC_DEVICE_LOCATOR:
2648 		rc = ipmi_sdr_print_sensor_generic_locator(intf,
2649 							   entry->record.
2650 							   genloc);
2651 		break;
2652 	case SDR_RECORD_TYPE_FRU_DEVICE_LOCATOR:
2653 		rc = ipmi_sdr_print_sensor_fru_locator(intf,
2654 						       entry->record.fruloc);
2655 		break;
2656 	case SDR_RECORD_TYPE_MC_DEVICE_LOCATOR:
2657 		rc = ipmi_sdr_print_sensor_mc_locator(intf,
2658 						      entry->record.mcloc);
2659 		break;
2660 	case SDR_RECORD_TYPE_ENTITY_ASSOC:
2661 		rc = ipmi_sdr_print_sensor_entity_assoc(intf,
2662 							entry->record.entassoc);
2663 		break;
2664 	case SDR_RECORD_TYPE_OEM:
2665 		rc = ipmi_sdr_print_sensor_oem(intf, entry->record.oem);
2666 		break;
2667 	case SDR_RECORD_TYPE_DEVICE_ENTITY_ASSOC:
2668 	case SDR_RECORD_TYPE_MC_CONFIRMATION:
2669 	case SDR_RECORD_TYPE_BMC_MSG_CHANNEL_INFO:
2670 		/* not implemented yet */
2671 		break;
2672 	}
2673 
2674 	return rc;
2675 }
2676 
2677 /* ipmi_sdr_print_sdr  -  iterate through SDR printing records
2678  *
2679  * intf:	ipmi interface
2680  * type:	record type to print
2681  *
2682  * returns 0 on success
2683  * returns -1 on error
2684  */
2685 int
2686 ipmi_sdr_print_sdr(struct ipmi_intf *intf, uint8_t type)
2687 {
2688 	struct sdr_get_rs *header;
2689 	struct sdr_record_list *e;
2690 	int rc = 0;
2691 
2692 	lprintf(LOG_DEBUG, "Querying SDR for sensor list");
2693 
2694 	if (sdr_list_itr == NULL) {
2695 		sdr_list_itr = ipmi_sdr_start(intf, 0);
2696 		if (sdr_list_itr == NULL) {
2697 			lprintf(LOG_ERR, "Unable to open SDR for reading");
2698 			return -1;
2699 		}
2700 	}
2701 
2702 	for (e = sdr_list_head; e != NULL; e = e->next) {
2703 		if (type != e->type && type != 0xff && type != 0xfe)
2704 			continue;
2705 		if (type == 0xfe &&
2706 		    e->type != SDR_RECORD_TYPE_FULL_SENSOR &&
2707 		    e->type != SDR_RECORD_TYPE_COMPACT_SENSOR)
2708 			continue;
2709 		if (ipmi_sdr_print_listentry(intf, e) < 0)
2710 			rc = -1;
2711 	}
2712 
2713 	while ((header = ipmi_sdr_get_next_header(intf, sdr_list_itr)) != NULL) {
2714 		uint8_t *rec;
2715 		struct sdr_record_list *sdrr;
2716 
2717 		rec = ipmi_sdr_get_record(intf, header, sdr_list_itr);
2718 		if (rec == NULL) {
2719 			lprintf(LOG_ERR, "ipmitool: ipmi_sdr_get_record() failed");
2720 			rc = -1;
2721 			continue;
2722 		}
2723 
2724 		sdrr = malloc(sizeof (struct sdr_record_list));
2725 		if (sdrr == NULL) {
2726 			lprintf(LOG_ERR, "ipmitool: malloc failure");
2727 			if (rec != NULL) {
2728 				free(rec);
2729 				rec = NULL;
2730 			}
2731 			break;
2732 		}
2733 		memset(sdrr, 0, sizeof (struct sdr_record_list));
2734 		sdrr->id = header->id;
2735 		sdrr->type = header->type;
2736 
2737 		switch (header->type) {
2738 		case SDR_RECORD_TYPE_FULL_SENSOR:
2739 		case SDR_RECORD_TYPE_COMPACT_SENSOR:
2740 			sdrr->record.common =
2741 			    (struct sdr_record_common_sensor *) rec;
2742 			break;
2743 		case SDR_RECORD_TYPE_EVENTONLY_SENSOR:
2744 			sdrr->record.eventonly =
2745 			    (struct sdr_record_eventonly_sensor *) rec;
2746 			break;
2747 		case SDR_RECORD_TYPE_GENERIC_DEVICE_LOCATOR:
2748 			sdrr->record.genloc =
2749 			    (struct sdr_record_generic_locator *) rec;
2750 			break;
2751 		case SDR_RECORD_TYPE_FRU_DEVICE_LOCATOR:
2752 			sdrr->record.fruloc =
2753 			    (struct sdr_record_fru_locator *) rec;
2754 			break;
2755 		case SDR_RECORD_TYPE_MC_DEVICE_LOCATOR:
2756 			sdrr->record.mcloc =
2757 			    (struct sdr_record_mc_locator *) rec;
2758 			break;
2759 		case SDR_RECORD_TYPE_ENTITY_ASSOC:
2760 			sdrr->record.entassoc =
2761 			    (struct sdr_record_entity_assoc *) rec;
2762 			break;
2763 		default:
2764 			free(rec);
2765 			rec = NULL;
2766 			if (sdrr != NULL) {
2767 				free(sdrr);
2768 				sdrr = NULL;
2769 			}
2770 			continue;
2771 		}
2772 
2773                 lprintf(LOG_DEBUG, "SDR record ID   : 0x%04x", sdrr->id);
2774 
2775 		if (type == header->type || type == 0xff ||
2776 		    (type == 0xfe &&
2777 		     (header->type == SDR_RECORD_TYPE_FULL_SENSOR ||
2778 		      header->type == SDR_RECORD_TYPE_COMPACT_SENSOR))) {
2779 			if (ipmi_sdr_print_rawentry(intf, header->type,
2780 						    rec, header->length) < 0)
2781 				rc = -1;
2782 		}
2783 
2784 		/* add to global record liset */
2785 		if (sdr_list_head == NULL)
2786 			sdr_list_head = sdrr;
2787 		else
2788 			sdr_list_tail->next = sdrr;
2789 
2790 		sdr_list_tail = sdrr;
2791 	}
2792 
2793 	return rc;
2794 }
2795 
2796 /* ipmi_sdr_get_reservation  -  Obtain SDR reservation ID
2797  *
2798  * @intf:	ipmi interface
2799  * @reserve_id:	pointer to short int for storing the id
2800  *
2801  * returns 0 on success
2802  * returns -1 on error
2803  */
2804 int
2805 ipmi_sdr_get_reservation(struct ipmi_intf *intf, int use_builtin,
2806                          uint16_t * reserve_id)
2807 {
2808 	struct ipmi_rs *rsp;
2809 	struct ipmi_rq req;
2810 
2811 	/* obtain reservation ID */
2812 	memset(&req, 0, sizeof (req));
2813 
2814 	if (use_builtin == 0) {
2815 		req.msg.netfn = IPMI_NETFN_STORAGE;
2816 	} else {
2817 		req.msg.netfn = IPMI_NETFN_SE;
2818 	}
2819 
2820 	req.msg.cmd = GET_SDR_RESERVE_REPO;
2821 	rsp = intf->sendrecv(intf, &req);
2822 
2823 	/* be slient for errors, they are handled by calling function */
2824 	if (rsp == NULL)
2825 		return -1;
2826 	if (rsp->ccode > 0)
2827 		return -1;
2828 
2829 	*reserve_id = ((struct sdr_reserve_repo_rs *) &(rsp->data))->reserve_id;
2830 	lprintf(LOG_DEBUG, "SDR reservation ID %04x", *reserve_id);
2831 
2832 	return 0;
2833 }
2834 
2835 /* ipmi_sdr_start  -  setup sdr iterator
2836  *
2837  * @intf:	ipmi interface
2838  *
2839  * returns sdr iterator structure pointer
2840  * returns NULL on error
2841  */
2842 struct ipmi_sdr_iterator *
2843 ipmi_sdr_start(struct ipmi_intf *intf, int use_builtin)
2844 {
2845 	struct ipmi_sdr_iterator *itr;
2846 	struct ipmi_rs *rsp;
2847 	struct ipmi_rq req;
2848 
2849 	struct ipm_devid_rsp *devid;
2850 
2851 	itr = malloc(sizeof (struct ipmi_sdr_iterator));
2852 	if (itr == NULL) {
2853 		lprintf(LOG_ERR, "ipmitool: malloc failure");
2854 		return NULL;
2855 	}
2856 
2857 	/* check SDRR capability */
2858 	memset(&req, 0, sizeof (req));
2859 	req.msg.netfn = IPMI_NETFN_APP;
2860 	req.msg.cmd = BMC_GET_DEVICE_ID;
2861 	req.msg.data_len = 0;
2862 
2863 	rsp = intf->sendrecv(intf, &req);
2864 
2865 	if (rsp == NULL) {
2866 		lprintf(LOG_ERR, "Get Device ID command failed");
2867 		free(itr);
2868 		itr = NULL;
2869 		return NULL;
2870 	}
2871 	if (rsp->ccode > 0) {
2872 		lprintf(LOG_ERR, "Get Device ID command failed: %#x %s",
2873 			rsp->ccode, val2str(rsp->ccode, completion_code_vals));
2874 		free(itr);
2875 		itr = NULL;
2876 		return NULL;
2877 	}
2878 	devid = (struct ipm_devid_rsp *) rsp->data;
2879 
2880    sdriana =  (long)IPM_DEV_MANUFACTURER_ID(devid->manufacturer_id);
2881 
2882 	if (!use_builtin && (devid->device_revision & IPM_DEV_DEVICE_ID_SDR_MASK)) {
2883 		if ((devid->adtl_device_support & 0x02) == 0) {
2884 			if ((devid->adtl_device_support & 0x01)) {
2885 				lprintf(LOG_DEBUG, "Using Device SDRs\n");
2886 				use_built_in = 1;
2887 			} else {
2888 				lprintf(LOG_ERR, "Error obtaining SDR info");
2889 				free(itr);
2890 				itr = NULL;
2891 				return NULL;
2892 			}
2893 		} else {
2894 			lprintf(LOG_DEBUG, "Using SDR from Repository \n");
2895 		}
2896 	}
2897 	itr->use_built_in = use_builtin ? 1 : use_built_in;
2898    /***********************/
2899 	if (itr->use_built_in == 0) {
2900 		struct sdr_repo_info_rs sdr_info;
2901 		/* get sdr repository info */
2902 		memset(&req, 0, sizeof (req));
2903 		req.msg.netfn = IPMI_NETFN_STORAGE;
2904 		req.msg.cmd = GET_SDR_REPO_INFO;
2905 
2906 		rsp = intf->sendrecv(intf, &req);
2907 		if (rsp == NULL) {
2908 			lprintf(LOG_ERR, "Error obtaining SDR info");
2909 			free(itr);
2910 			itr = NULL;
2911 			return NULL;
2912 		}
2913 		if (rsp->ccode > 0) {
2914 			lprintf(LOG_ERR, "Error obtaining SDR info: %s",
2915 				val2str(rsp->ccode, completion_code_vals));
2916 			free(itr);
2917 			itr = NULL;
2918 			return NULL;
2919 		}
2920 
2921 		memcpy(&sdr_info, rsp->data, sizeof (sdr_info));
2922 		/* IPMIv1.0 == 0x01
2923 		   * IPMIv1.5 == 0x51
2924 		   * IPMIv2.0 == 0x02
2925 		 */
2926 		if ((sdr_info.version != 0x51) &&
2927 		    (sdr_info.version != 0x01) &&
2928 		    (sdr_info.version != 0x02)) {
2929 			lprintf(LOG_WARN, "WARNING: Unknown SDR repository "
2930 				"version 0x%02x", sdr_info.version);
2931 		}
2932 
2933 		itr->total = sdr_info.count;
2934 		itr->next = 0;
2935 
2936 		lprintf(LOG_DEBUG, "SDR free space: %d", sdr_info.free);
2937 		lprintf(LOG_DEBUG, "SDR records   : %d", sdr_info.count);
2938 
2939 		/* Build SDRR if there is no record in repository */
2940 		if( sdr_info.count == 0 ) {
2941 		   lprintf(LOG_DEBUG, "Rebuilding SDRR...");
2942 
2943 		   if( ipmi_sdr_add_from_sensors( intf, 0 ) != 0 ) {
2944 		      lprintf(LOG_ERR, "Could not build SDRR!");
2945 		      free(itr);
2946 					itr = NULL;
2947 		      return NULL;
2948 		   }
2949 		}
2950 	} else {
2951 		struct sdr_device_info_rs sdr_info;
2952 		/* get device sdr info */
2953 		memset(&req, 0, sizeof (req));
2954 		req.msg.netfn = IPMI_NETFN_SE;
2955 		req.msg.cmd = GET_DEVICE_SDR_INFO;
2956 
2957 		rsp = intf->sendrecv(intf, &req);
2958 		if (!rsp || !rsp->data_len || rsp->ccode) {
2959 			printf("Err in cmd get sensor sdr info\n");
2960 			free(itr);
2961 			itr = NULL;
2962 			return NULL;
2963 		}
2964 		memcpy(&sdr_info, rsp->data, sizeof (sdr_info));
2965 
2966 		itr->total = sdr_info.count;
2967 		itr->next = 0;
2968 		lprintf(LOG_DEBUG, "SDR records   : %d", sdr_info.count);
2969 	}
2970 
2971 	if (ipmi_sdr_get_reservation(intf, itr->use_built_in,
2972                                 &(itr->reservation)) < 0) {
2973 		lprintf(LOG_ERR, "Unable to obtain SDR reservation");
2974 		free(itr);
2975 		itr = NULL;
2976 		return NULL;
2977 	}
2978 
2979 	return itr;
2980 }
2981 
2982 /* ipmi_sdr_get_record  -  return RAW SDR record
2983  *
2984  * @intf:	ipmi interface
2985  * @header:	SDR header
2986  * @itr:	SDR iterator
2987  *
2988  * returns raw SDR data
2989  * returns NULL on error
2990  */
2991 uint8_t *
2992 ipmi_sdr_get_record(struct ipmi_intf * intf, struct sdr_get_rs * header,
2993 		    struct ipmi_sdr_iterator * itr)
2994 {
2995 	struct ipmi_rq req;
2996 	struct ipmi_rs *rsp;
2997 	struct sdr_get_rq sdr_rq;
2998 	uint8_t *data;
2999 	int i = 0, len = header->length;
3000 
3001 	if (len < 1)
3002 		return NULL;
3003 
3004 	data = malloc(len + 1);
3005 	if (data == NULL) {
3006 		lprintf(LOG_ERR, "ipmitool: malloc failure");
3007 		return NULL;
3008 	}
3009 	memset(data, 0, len + 1);
3010 
3011 	memset(&sdr_rq, 0, sizeof (sdr_rq));
3012 	sdr_rq.reserve_id = itr->reservation;
3013 	sdr_rq.id = header->id;
3014 	sdr_rq.offset = 0;
3015 
3016 	memset(&req, 0, sizeof (req));
3017 	if (itr->use_built_in == 0) {
3018 		req.msg.netfn = IPMI_NETFN_STORAGE;
3019 		req.msg.cmd = GET_SDR;
3020 	} else {
3021 		req.msg.netfn = IPMI_NETFN_SE;
3022 		req.msg.cmd = GET_DEVICE_SDR;
3023 	}
3024 	req.msg.data = (uint8_t *) & sdr_rq;
3025 	req.msg.data_len = sizeof (sdr_rq);
3026 
3027 	/* check if max length is null */
3028 	if ( sdr_max_read_len == 0 ) {
3029 		/* get maximum response size */
3030 		sdr_max_read_len = ipmi_intf_get_max_response_data_size(intf) - 2;
3031 
3032 		/* cap the number of bytes to read */
3033 		if (sdr_max_read_len > 0xFE) {
3034 			sdr_max_read_len = 0xFE;
3035 		}
3036 	}
3037 
3038 	/* read SDR record with partial reads
3039 	 * because a full read usually exceeds the maximum
3040 	 * transport buffer size.  (completion code 0xca)
3041 	 */
3042 	while (i < len) {
3043 		sdr_rq.length = (len - i < sdr_max_read_len) ?
3044 		    len - i : sdr_max_read_len;
3045 		sdr_rq.offset = i + 5;	/* 5 header bytes */
3046 
3047 		lprintf(LOG_DEBUG, "Getting %d bytes from SDR at offset %d",
3048 			sdr_rq.length, sdr_rq.offset);
3049 
3050 		rsp = intf->sendrecv(intf, &req);
3051 		if (rsp == NULL) {
3052 		    sdr_max_read_len = sdr_rq.length - 1;
3053 		    if (sdr_max_read_len > 0) {
3054 			/* no response may happen if requests are bridged
3055 			   and too many bytes are requested */
3056 			continue;
3057 		    } else {
3058 			free(data);
3059 			data = NULL;
3060 			return NULL;
3061 		    }
3062 		}
3063 
3064 		switch (rsp->ccode) {
3065 		case 0xca:
3066 			/* read too many bytes at once */
3067 			sdr_max_read_len = sdr_rq.length - 1;
3068 			continue;
3069 		case 0xc5:
3070 			/* lost reservation */
3071 			lprintf(LOG_DEBUG, "SDR reservation cancelled. "
3072 				"Sleeping a bit and retrying...");
3073 
3074 			sleep(rand() & 3);
3075 
3076 			if (ipmi_sdr_get_reservation(intf, itr->use_built_in,
3077                                       &(itr->reservation)) < 0) {
3078 				free(data);
3079 				data = NULL;
3080 				return NULL;
3081 			}
3082 			sdr_rq.reserve_id = itr->reservation;
3083 			continue;
3084 		}
3085 
3086 		/* special completion codes handled above */
3087 		if (rsp->ccode > 0 || rsp->data_len == 0) {
3088 			free(data);
3089 			data = NULL;
3090 			return NULL;
3091 		}
3092 
3093 		memcpy(data + i, rsp->data + 2, sdr_rq.length);
3094 		i += sdr_max_read_len;
3095 	}
3096 
3097 	return data;
3098 }
3099 
3100 /* ipmi_sdr_end  -  cleanup SDR iterator
3101  *
3102  * @intf:	ipmi interface
3103  * @itr:	SDR iterator
3104  *
3105  * no meaningful return code
3106  */
3107 void
3108 ipmi_sdr_end(struct ipmi_intf *intf, struct ipmi_sdr_iterator *itr)
3109 {
3110 	if (itr) {
3111 		free(itr);
3112 		itr = NULL;
3113 	}
3114 }
3115 
3116 /* __sdr_list_add  -  helper function to add SDR record to list
3117  *
3118  * @head:	list head
3119  * @entry:	new entry to add to end of list
3120  *
3121  * returns 0 on success
3122  * returns -1 on error
3123  */
3124 static int
3125 __sdr_list_add(struct sdr_record_list *head, struct sdr_record_list *entry)
3126 {
3127 	struct sdr_record_list *e;
3128 	struct sdr_record_list *new;
3129 
3130 	if (head == NULL)
3131 		return -1;
3132 
3133 	new = malloc(sizeof (struct sdr_record_list));
3134 	if (new == NULL) {
3135 		lprintf(LOG_ERR, "ipmitool: malloc failure");
3136 		return -1;
3137 	}
3138 	memcpy(new, entry, sizeof (struct sdr_record_list));
3139 
3140 	e = head;
3141 	while (e->next)
3142 		e = e->next;
3143 	e->next = new;
3144 	new->next = NULL;
3145 
3146 	return 0;
3147 }
3148 
3149 /* __sdr_list_empty  -  low-level handler to clean up record list
3150  *
3151  * @head:	list head to clean
3152  *
3153  * no meaningful return code
3154  */
3155 static void
3156 __sdr_list_empty(struct sdr_record_list *head)
3157 {
3158 	struct sdr_record_list *e, *f;
3159 	for (e = head; e != NULL; e = f) {
3160 		f = e->next;
3161 		free(e);
3162 		e = NULL;
3163 	}
3164 	head = NULL;
3165 }
3166 
3167 /* ipmi_sdr_list_empty  -  clean global SDR list
3168  *
3169  * @intf:	ipmi interface
3170  *
3171  * no meaningful return code
3172  */
3173 void
3174 ipmi_sdr_list_empty(struct ipmi_intf *intf)
3175 {
3176 	struct sdr_record_list *list, *next;
3177 
3178 	ipmi_sdr_end(intf, sdr_list_itr);
3179 
3180 	for (list = sdr_list_head; list != NULL; list = next) {
3181 		switch (list->type) {
3182 		case SDR_RECORD_TYPE_FULL_SENSOR:
3183 		case SDR_RECORD_TYPE_COMPACT_SENSOR:
3184 			if (list->record.common) {
3185 				free(list->record.common);
3186 				list->record.common = NULL;
3187 			}
3188 			break;
3189 		case SDR_RECORD_TYPE_EVENTONLY_SENSOR:
3190 			if (list->record.eventonly) {
3191 				free(list->record.eventonly);
3192 				list->record.eventonly = NULL;
3193 			}
3194 			break;
3195 		case SDR_RECORD_TYPE_GENERIC_DEVICE_LOCATOR:
3196 			if (list->record.genloc) {
3197 				free(list->record.genloc);
3198 				list->record.genloc = NULL;
3199 			}
3200 			break;
3201 		case SDR_RECORD_TYPE_FRU_DEVICE_LOCATOR:
3202 			if (list->record.fruloc) {
3203 				free(list->record.fruloc);
3204 				list->record.fruloc = NULL;
3205 			}
3206 			break;
3207 		case SDR_RECORD_TYPE_MC_DEVICE_LOCATOR:
3208 			if (list->record.mcloc) {
3209 				free(list->record.mcloc);
3210 				list->record.mcloc = NULL;
3211 			}
3212 			break;
3213 		case SDR_RECORD_TYPE_ENTITY_ASSOC:
3214 			if (list->record.entassoc) {
3215 				free(list->record.entassoc);
3216 				list->record.entassoc = NULL;
3217 			}
3218 			break;
3219 		}
3220 		next = list->next;
3221 		free(list);
3222 		list = NULL;
3223 	}
3224 
3225 	sdr_list_head = NULL;
3226 	sdr_list_tail = NULL;
3227 	sdr_list_itr = NULL;
3228 }
3229 
3230 /* ipmi_sdr_find_sdr_bynumtype  -  lookup SDR entry by number/type
3231  *
3232  * @intf:	ipmi interface
3233  * @gen_id:	sensor owner ID/LUN - SEL generator ID
3234  * @num:	sensor number to search for
3235  * @type:	sensor type to search for
3236  *
3237  * returns pointer to SDR list
3238  * returns NULL on error
3239  */
3240 struct sdr_record_list *
3241 ipmi_sdr_find_sdr_bynumtype(struct ipmi_intf *intf, uint16_t gen_id, uint8_t num, uint8_t type)
3242 {
3243 	struct sdr_get_rs *header;
3244 	struct sdr_record_list *e;
3245 	int found = 0;
3246 
3247 	if (sdr_list_itr == NULL) {
3248 		sdr_list_itr = ipmi_sdr_start(intf, 0);
3249 		if (sdr_list_itr == NULL) {
3250 			lprintf(LOG_ERR, "Unable to open SDR for reading");
3251 			return NULL;
3252 		}
3253 	}
3254 
3255 	/* check what we've already read */
3256 	for (e = sdr_list_head; e != NULL; e = e->next) {
3257 		switch (e->type) {
3258 		case SDR_RECORD_TYPE_FULL_SENSOR:
3259 		case SDR_RECORD_TYPE_COMPACT_SENSOR:
3260 			if (e->record.common->keys.sensor_num == num &&
3261 			    e->record.common->keys.owner_id == (gen_id & 0x00ff) &&
3262 			    e->record.common->sensor.type == type)
3263 				return e;
3264 			break;
3265 		case SDR_RECORD_TYPE_EVENTONLY_SENSOR:
3266 			if (e->record.eventonly->keys.sensor_num == num &&
3267 			    e->record.eventonly->keys.owner_id == (gen_id & 0x00ff) &&
3268 			    e->record.eventonly->sensor_type == type)
3269 				return e;
3270 			break;
3271 		}
3272 	}
3273 
3274 	/* now keep looking */
3275 	while ((header = ipmi_sdr_get_next_header(intf, sdr_list_itr)) != NULL) {
3276 		uint8_t *rec;
3277 		struct sdr_record_list *sdrr;
3278 
3279 		sdrr = malloc(sizeof (struct sdr_record_list));
3280 		if (sdrr == NULL) {
3281 			lprintf(LOG_ERR, "ipmitool: malloc failure");
3282 			break;
3283 		}
3284 		memset(sdrr, 0, sizeof (struct sdr_record_list));
3285 		sdrr->id = header->id;
3286 		sdrr->type = header->type;
3287 
3288 		rec = ipmi_sdr_get_record(intf, header, sdr_list_itr);
3289 		if (rec == NULL) {
3290 			if (sdrr != NULL) {
3291 				free(sdrr);
3292 				sdrr = NULL;
3293 			}
3294 			continue;
3295 		}
3296 
3297 		switch (header->type) {
3298 		case SDR_RECORD_TYPE_FULL_SENSOR:
3299 		case SDR_RECORD_TYPE_COMPACT_SENSOR:
3300 			sdrr->record.common =
3301 			    (struct sdr_record_common_sensor *) rec;
3302 			if (sdrr->record.common->keys.sensor_num == num
3303 			    && sdrr->record.common->keys.owner_id == (gen_id & 0x00ff)
3304 			    && sdrr->record.common->sensor.type == type)
3305 				found = 1;
3306 			break;
3307 		case SDR_RECORD_TYPE_EVENTONLY_SENSOR:
3308 			sdrr->record.eventonly =
3309 			    (struct sdr_record_eventonly_sensor *) rec;
3310 			if (sdrr->record.eventonly->keys.sensor_num == num
3311 			    && sdrr->record.eventonly->keys.owner_id == (gen_id & 0x00ff)
3312 			    && sdrr->record.eventonly->sensor_type == type)
3313 				found = 1;
3314 			break;
3315 		case SDR_RECORD_TYPE_GENERIC_DEVICE_LOCATOR:
3316 			sdrr->record.genloc =
3317 			    (struct sdr_record_generic_locator *) rec;
3318 			break;
3319 		case SDR_RECORD_TYPE_FRU_DEVICE_LOCATOR:
3320 			sdrr->record.fruloc =
3321 			    (struct sdr_record_fru_locator *) rec;
3322 			break;
3323 		case SDR_RECORD_TYPE_MC_DEVICE_LOCATOR:
3324 			sdrr->record.mcloc =
3325 			    (struct sdr_record_mc_locator *) rec;
3326 			break;
3327 		case SDR_RECORD_TYPE_ENTITY_ASSOC:
3328 			sdrr->record.entassoc =
3329 			    (struct sdr_record_entity_assoc *) rec;
3330 			break;
3331 		default:
3332 			free(rec);
3333 			rec = NULL;
3334 			if (sdrr != NULL) {
3335 				free(sdrr);
3336 				sdrr = NULL;
3337 			}
3338 			continue;
3339 		}
3340 
3341 		/* put in the global record list */
3342 		if (sdr_list_head == NULL)
3343 			sdr_list_head = sdrr;
3344 		else
3345 			sdr_list_tail->next = sdrr;
3346 
3347 		sdr_list_tail = sdrr;
3348 
3349 		if (found)
3350 			return sdrr;
3351 	}
3352 
3353 	return NULL;
3354 }
3355 
3356 /* ipmi_sdr_find_sdr_bysensortype  -  lookup SDR entry by sensor type
3357  *
3358  * @intf:	ipmi interface
3359  * @type:	sensor type to search for
3360  *
3361  * returns pointer to SDR list
3362  * returns NULL on error
3363  */
3364 struct sdr_record_list *
3365 ipmi_sdr_find_sdr_bysensortype(struct ipmi_intf *intf, uint8_t type)
3366 {
3367 	struct sdr_record_list *head;
3368 	struct sdr_get_rs *header;
3369 	struct sdr_record_list *e;
3370 
3371 	if (sdr_list_itr == NULL) {
3372 		sdr_list_itr = ipmi_sdr_start(intf, 0);
3373 		if (sdr_list_itr == NULL) {
3374 			lprintf(LOG_ERR, "Unable to open SDR for reading");
3375 			return NULL;
3376 		}
3377 	}
3378 
3379 	/* check what we've already read */
3380 	head = malloc(sizeof (struct sdr_record_list));
3381 	if (head == NULL) {
3382 		lprintf(LOG_ERR, "ipmitool: malloc failure");
3383 		return NULL;
3384 	}
3385 	memset(head, 0, sizeof (struct sdr_record_list));
3386 
3387 	for (e = sdr_list_head; e != NULL; e = e->next) {
3388 		switch (e->type) {
3389 		case SDR_RECORD_TYPE_FULL_SENSOR:
3390 		case SDR_RECORD_TYPE_COMPACT_SENSOR:
3391 			if (e->record.common->sensor.type == type)
3392 				__sdr_list_add(head, e);
3393 			break;
3394 		case SDR_RECORD_TYPE_EVENTONLY_SENSOR:
3395 			if (e->record.eventonly->sensor_type == type)
3396 				__sdr_list_add(head, e);
3397 			break;
3398 		}
3399 	}
3400 
3401 	/* now keep looking */
3402 	while ((header = ipmi_sdr_get_next_header(intf, sdr_list_itr)) != NULL) {
3403 		uint8_t *rec;
3404 		struct sdr_record_list *sdrr;
3405 
3406 		sdrr = malloc(sizeof (struct sdr_record_list));
3407 		if (sdrr == NULL) {
3408 			lprintf(LOG_ERR, "ipmitool: malloc failure");
3409 			break;
3410 		}
3411 		memset(sdrr, 0, sizeof (struct sdr_record_list));
3412 		sdrr->id = header->id;
3413 		sdrr->type = header->type;
3414 
3415 		rec = ipmi_sdr_get_record(intf, header, sdr_list_itr);
3416 		if (rec == NULL) {
3417 			if (sdrr != NULL) {
3418 				free(sdrr);
3419 				sdrr = NULL;
3420 			}
3421 			continue;
3422 		}
3423 
3424 		switch (header->type) {
3425 		case SDR_RECORD_TYPE_FULL_SENSOR:
3426 		case SDR_RECORD_TYPE_COMPACT_SENSOR:
3427 			sdrr->record.common =
3428 			    (struct sdr_record_common_sensor *) rec;
3429 			if (sdrr->record.common->sensor.type == type)
3430 				__sdr_list_add(head, sdrr);
3431 			break;
3432 		case SDR_RECORD_TYPE_EVENTONLY_SENSOR:
3433 			sdrr->record.eventonly =
3434 			    (struct sdr_record_eventonly_sensor *) rec;
3435 			if (sdrr->record.eventonly->sensor_type == type)
3436 				__sdr_list_add(head, sdrr);
3437 			break;
3438 		case SDR_RECORD_TYPE_GENERIC_DEVICE_LOCATOR:
3439 			sdrr->record.genloc =
3440 			    (struct sdr_record_generic_locator *) rec;
3441 			break;
3442 		case SDR_RECORD_TYPE_FRU_DEVICE_LOCATOR:
3443 			sdrr->record.fruloc =
3444 			    (struct sdr_record_fru_locator *) rec;
3445 			break;
3446 		case SDR_RECORD_TYPE_MC_DEVICE_LOCATOR:
3447 			sdrr->record.mcloc =
3448 			    (struct sdr_record_mc_locator *) rec;
3449 			break;
3450 		case SDR_RECORD_TYPE_ENTITY_ASSOC:
3451 			sdrr->record.entassoc =
3452 			    (struct sdr_record_entity_assoc *) rec;
3453 			break;
3454 		default:
3455 			free(rec);
3456 			rec = NULL;
3457 			if (sdrr != NULL) {
3458 				free(sdrr);
3459 				sdrr = NULL;
3460 			}
3461 			continue;
3462 		}
3463 
3464 		/* put in the global record list */
3465 		if (sdr_list_head == NULL)
3466 			sdr_list_head = sdrr;
3467 		else
3468 			sdr_list_tail->next = sdrr;
3469 
3470 		sdr_list_tail = sdrr;
3471 	}
3472 
3473 	return head;
3474 }
3475 
3476 /* ipmi_sdr_find_sdr_byentity  -  lookup SDR entry by entity association
3477  *
3478  * @intf:	ipmi interface
3479  * @entity:	entity id/instance to search for
3480  *
3481  * returns pointer to SDR list
3482  * returns NULL on error
3483  */
3484 struct sdr_record_list *
3485 ipmi_sdr_find_sdr_byentity(struct ipmi_intf *intf, struct entity_id *entity)
3486 {
3487 	struct sdr_get_rs *header;
3488 	struct sdr_record_list *e;
3489 	struct sdr_record_list *head;
3490 
3491 	if (sdr_list_itr == NULL) {
3492 		sdr_list_itr = ipmi_sdr_start(intf, 0);
3493 		if (sdr_list_itr == NULL) {
3494 			lprintf(LOG_ERR, "Unable to open SDR for reading");
3495 			return NULL;
3496 		}
3497 	}
3498 
3499 	head = malloc(sizeof (struct sdr_record_list));
3500 	if (head == NULL) {
3501 		lprintf(LOG_ERR, "ipmitool: malloc failure");
3502 		return NULL;
3503 	}
3504 	memset(head, 0, sizeof (struct sdr_record_list));
3505 
3506 	/* check what we've already read */
3507 	for (e = sdr_list_head; e != NULL; e = e->next) {
3508 		switch (e->type) {
3509 		case SDR_RECORD_TYPE_FULL_SENSOR:
3510 		case SDR_RECORD_TYPE_COMPACT_SENSOR:
3511 			if (e->record.common->entity.id == entity->id &&
3512 			    (entity->instance == 0x7f ||
3513 			     e->record.common->entity.instance ==
3514 			     entity->instance))
3515 				__sdr_list_add(head, e);
3516 			break;
3517 		case SDR_RECORD_TYPE_EVENTONLY_SENSOR:
3518 			if (e->record.eventonly->entity.id == entity->id &&
3519 			    (entity->instance == 0x7f ||
3520 			     e->record.eventonly->entity.instance ==
3521 			     entity->instance))
3522 				__sdr_list_add(head, e);
3523 			break;
3524 		case SDR_RECORD_TYPE_GENERIC_DEVICE_LOCATOR:
3525 			if (e->record.genloc->entity.id == entity->id &&
3526 			    (entity->instance == 0x7f ||
3527 			     e->record.genloc->entity.instance ==
3528 			     entity->instance))
3529 				__sdr_list_add(head, e);
3530 			break;
3531 		case SDR_RECORD_TYPE_FRU_DEVICE_LOCATOR:
3532 			if (e->record.fruloc->entity.id == entity->id &&
3533 			    (entity->instance == 0x7f ||
3534 			     e->record.fruloc->entity.instance ==
3535 			     entity->instance))
3536 				__sdr_list_add(head, e);
3537 			break;
3538 		case SDR_RECORD_TYPE_MC_DEVICE_LOCATOR:
3539 			if (e->record.mcloc->entity.id == entity->id &&
3540 			    (entity->instance == 0x7f ||
3541 			     e->record.mcloc->entity.instance ==
3542 			     entity->instance))
3543 				__sdr_list_add(head, e);
3544 			break;
3545 		case SDR_RECORD_TYPE_ENTITY_ASSOC:
3546 			if (e->record.entassoc->entity.id == entity->id &&
3547 			    (entity->instance == 0x7f ||
3548 			     e->record.entassoc->entity.instance ==
3549 			     entity->instance))
3550 				__sdr_list_add(head, e);
3551 			break;
3552 		}
3553 	}
3554 
3555 	/* now keep looking */
3556 	while ((header = ipmi_sdr_get_next_header(intf, sdr_list_itr)) != NULL) {
3557 		uint8_t *rec;
3558 		struct sdr_record_list *sdrr;
3559 
3560 		sdrr = malloc(sizeof (struct sdr_record_list));
3561 		if (sdrr == NULL) {
3562 			lprintf(LOG_ERR, "ipmitool: malloc failure");
3563 			break;
3564 		}
3565 		memset(sdrr, 0, sizeof (struct sdr_record_list));
3566 		sdrr->id = header->id;
3567 		sdrr->type = header->type;
3568 
3569 		rec = ipmi_sdr_get_record(intf, header, sdr_list_itr);
3570 		if (rec == NULL) {
3571 			if (sdrr != NULL) {
3572 				free(sdrr);
3573 				sdrr = NULL;
3574 			}
3575 			continue;
3576 		}
3577 
3578 		switch (header->type) {
3579 		case SDR_RECORD_TYPE_FULL_SENSOR:
3580 		case SDR_RECORD_TYPE_COMPACT_SENSOR:
3581 			sdrr->record.common =
3582 			    (struct sdr_record_common_sensor *) rec;
3583 			if (sdrr->record.common->entity.id == entity->id
3584 			    && (entity->instance == 0x7f
3585 				|| sdrr->record.common->entity.instance ==
3586 				entity->instance))
3587 				__sdr_list_add(head, sdrr);
3588 			break;
3589 		case SDR_RECORD_TYPE_EVENTONLY_SENSOR:
3590 			sdrr->record.eventonly =
3591 			    (struct sdr_record_eventonly_sensor *) rec;
3592 			if (sdrr->record.eventonly->entity.id == entity->id
3593 			    && (entity->instance == 0x7f
3594 				|| sdrr->record.eventonly->entity.instance ==
3595 				entity->instance))
3596 				__sdr_list_add(head, sdrr);
3597 			break;
3598 		case SDR_RECORD_TYPE_GENERIC_DEVICE_LOCATOR:
3599 			sdrr->record.genloc =
3600 			    (struct sdr_record_generic_locator *) rec;
3601 			if (sdrr->record.genloc->entity.id == entity->id
3602 			    && (entity->instance == 0x7f
3603 				|| sdrr->record.genloc->entity.instance ==
3604 				entity->instance))
3605 				__sdr_list_add(head, sdrr);
3606 			break;
3607 		case SDR_RECORD_TYPE_FRU_DEVICE_LOCATOR:
3608 			sdrr->record.fruloc =
3609 			    (struct sdr_record_fru_locator *) rec;
3610 			if (sdrr->record.fruloc->entity.id == entity->id
3611 			    && (entity->instance == 0x7f
3612 				|| sdrr->record.fruloc->entity.instance ==
3613 				entity->instance))
3614 				__sdr_list_add(head, sdrr);
3615 			break;
3616 		case SDR_RECORD_TYPE_MC_DEVICE_LOCATOR:
3617 			sdrr->record.mcloc =
3618 			    (struct sdr_record_mc_locator *) rec;
3619 			if (sdrr->record.mcloc->entity.id == entity->id
3620 			    && (entity->instance == 0x7f
3621 				|| sdrr->record.mcloc->entity.instance ==
3622 				entity->instance))
3623 				__sdr_list_add(head, sdrr);
3624 			break;
3625 		case SDR_RECORD_TYPE_ENTITY_ASSOC:
3626 			sdrr->record.entassoc =
3627 			    (struct sdr_record_entity_assoc *) rec;
3628 			if (sdrr->record.entassoc->entity.id == entity->id
3629 			    && (entity->instance == 0x7f
3630 				|| sdrr->record.entassoc->entity.instance ==
3631 				entity->instance))
3632 				__sdr_list_add(head, sdrr);
3633 			break;
3634 		default:
3635 			free(rec);
3636 			rec = NULL;
3637 			if (sdrr != NULL) {
3638 				free(sdrr);
3639 				sdrr = NULL;
3640 			}
3641 			continue;
3642 		}
3643 
3644 		/* add to global record list */
3645 		if (sdr_list_head == NULL)
3646 			sdr_list_head = sdrr;
3647 		else
3648 			sdr_list_tail->next = sdrr;
3649 
3650 		sdr_list_tail = sdrr;
3651 	}
3652 
3653 	return head;
3654 }
3655 
3656 /* ipmi_sdr_find_sdr_bytype  -  lookup SDR entries by type
3657  *
3658  * @intf:	ipmi interface
3659  * @type:	type of sensor record to search for
3660  *
3661  * returns pointer to SDR list with all matching entities
3662  * returns NULL on error
3663  */
3664 struct sdr_record_list *
3665 ipmi_sdr_find_sdr_bytype(struct ipmi_intf *intf, uint8_t type)
3666 {
3667 	struct sdr_get_rs *header;
3668 	struct sdr_record_list *e;
3669 	struct sdr_record_list *head;
3670 
3671 	if (sdr_list_itr == NULL) {
3672 		sdr_list_itr = ipmi_sdr_start(intf, 0);
3673 		if (sdr_list_itr == NULL) {
3674 			lprintf(LOG_ERR, "Unable to open SDR for reading");
3675 			return NULL;
3676 		}
3677 	}
3678 
3679 	head = malloc(sizeof (struct sdr_record_list));
3680 	if (head == NULL) {
3681 		lprintf(LOG_ERR, "ipmitool: malloc failure");
3682 		return NULL;
3683 	}
3684 	memset(head, 0, sizeof (struct sdr_record_list));
3685 
3686 	/* check what we've already read */
3687 	for (e = sdr_list_head; e != NULL; e = e->next)
3688 		if (e->type == type)
3689 			__sdr_list_add(head, e);
3690 
3691 	/* now keep looking */
3692 	while ((header = ipmi_sdr_get_next_header(intf, sdr_list_itr)) != NULL) {
3693 		uint8_t *rec;
3694 		struct sdr_record_list *sdrr;
3695 
3696 		sdrr = malloc(sizeof (struct sdr_record_list));
3697 		if (sdrr == NULL) {
3698 			lprintf(LOG_ERR, "ipmitool: malloc failure");
3699 			break;
3700 		}
3701 		memset(sdrr, 0, sizeof (struct sdr_record_list));
3702 		sdrr->id = header->id;
3703 		sdrr->type = header->type;
3704 
3705 		rec = ipmi_sdr_get_record(intf, header, sdr_list_itr);
3706 		if (rec == NULL) {
3707 			if (sdrr != NULL) {
3708 				free(sdrr);
3709 				sdrr = NULL;
3710 			}
3711 			continue;
3712 		}
3713 
3714 		switch (header->type) {
3715 		case SDR_RECORD_TYPE_FULL_SENSOR:
3716 		case SDR_RECORD_TYPE_COMPACT_SENSOR:
3717 			sdrr->record.common =
3718 			    (struct sdr_record_common_sensor *) rec;
3719 			break;
3720 		case SDR_RECORD_TYPE_EVENTONLY_SENSOR:
3721 			sdrr->record.eventonly =
3722 			    (struct sdr_record_eventonly_sensor *) rec;
3723 			break;
3724 		case SDR_RECORD_TYPE_GENERIC_DEVICE_LOCATOR:
3725 			sdrr->record.genloc =
3726 			    (struct sdr_record_generic_locator *) rec;
3727 			break;
3728 		case SDR_RECORD_TYPE_FRU_DEVICE_LOCATOR:
3729 			sdrr->record.fruloc =
3730 			    (struct sdr_record_fru_locator *) rec;
3731 			break;
3732 		case SDR_RECORD_TYPE_MC_DEVICE_LOCATOR:
3733 			sdrr->record.mcloc =
3734 			    (struct sdr_record_mc_locator *) rec;
3735 			break;
3736 		case SDR_RECORD_TYPE_ENTITY_ASSOC:
3737 			sdrr->record.entassoc =
3738 			    (struct sdr_record_entity_assoc *) rec;
3739 			break;
3740 		default:
3741 			free(rec);
3742 			rec = NULL;
3743 			if (sdrr != NULL) {
3744 				free(sdrr);
3745 				sdrr = NULL;
3746 			}
3747 			continue;
3748 		}
3749 
3750 		if (header->type == type)
3751 			__sdr_list_add(head, sdrr);
3752 
3753 		/* add to global record list */
3754 		if (sdr_list_head == NULL)
3755 			sdr_list_head = sdrr;
3756 		else
3757 			sdr_list_tail->next = sdrr;
3758 
3759 		sdr_list_tail = sdrr;
3760 	}
3761 
3762 	return head;
3763 }
3764 
3765 /* ipmi_sdr_find_sdr_byid  -  lookup SDR entry by ID string
3766  *
3767  * @intf:	ipmi interface
3768  * @id:		string to match for sensor name
3769  *
3770  * returns pointer to SDR list
3771  * returns NULL on error
3772  */
3773 struct sdr_record_list *
3774 ipmi_sdr_find_sdr_byid(struct ipmi_intf *intf, char *id)
3775 {
3776 	struct sdr_get_rs *header;
3777 	struct sdr_record_list *e;
3778 	int found = 0;
3779 	int idlen;
3780 
3781 	if (id == NULL)
3782 		return NULL;
3783 
3784 	idlen = strlen(id);
3785 
3786 	if (sdr_list_itr == NULL) {
3787 		sdr_list_itr = ipmi_sdr_start(intf, 0);
3788 		if (sdr_list_itr == NULL) {
3789 			lprintf(LOG_ERR, "Unable to open SDR for reading");
3790 			return NULL;
3791 		}
3792 	}
3793 
3794 	/* check what we've already read */
3795 	for (e = sdr_list_head; e != NULL; e = e->next) {
3796 		switch (e->type) {
3797 		case SDR_RECORD_TYPE_FULL_SENSOR:
3798 			if (!strncmp((const char *)e->record.full->id_string,
3799 				     (const char *)id,
3800 				     __max(e->record.full->id_code & 0x1f, idlen)))
3801 				return e;
3802 			break;
3803 		case SDR_RECORD_TYPE_COMPACT_SENSOR:
3804 			if (!strncmp((const char *)e->record.compact->id_string,
3805 				     (const char *)id,
3806 				     __max(e->record.compact->id_code & 0x1f, idlen)))
3807 				return e;
3808 			break;
3809 		case SDR_RECORD_TYPE_EVENTONLY_SENSOR:
3810 			if (!strncmp((const char *)e->record.eventonly->id_string,
3811 				     (const char *)id,
3812 				     __max(e->record.eventonly->id_code & 0x1f, idlen)))
3813 				return e;
3814 			break;
3815 		case SDR_RECORD_TYPE_GENERIC_DEVICE_LOCATOR:
3816 			if (!strncmp((const char *)e->record.genloc->id_string,
3817 				     (const char *)id,
3818 				     __max(e->record.genloc->id_code & 0x1f, idlen)))
3819 				return e;
3820 			break;
3821 		case SDR_RECORD_TYPE_FRU_DEVICE_LOCATOR:
3822 			if (!strncmp((const char *)e->record.fruloc->id_string,
3823 				     (const char *)id,
3824 				     __max(e->record.fruloc->id_code & 0x1f, idlen)))
3825 				return e;
3826 			break;
3827 		case SDR_RECORD_TYPE_MC_DEVICE_LOCATOR:
3828 			if (!strncmp((const char *)e->record.mcloc->id_string,
3829 				     (const char *)id,
3830 				     __max(e->record.mcloc->id_code & 0x1f, idlen)))
3831 				return e;
3832 			break;
3833 		}
3834 	}
3835 
3836 	/* now keep looking */
3837 	while ((header = ipmi_sdr_get_next_header(intf, sdr_list_itr)) != NULL) {
3838 		uint8_t *rec;
3839 		struct sdr_record_list *sdrr;
3840 
3841 		sdrr = malloc(sizeof (struct sdr_record_list));
3842 		if (sdrr == NULL) {
3843 			lprintf(LOG_ERR, "ipmitool: malloc failure");
3844 			break;
3845 		}
3846 		memset(sdrr, 0, sizeof (struct sdr_record_list));
3847 		sdrr->id = header->id;
3848 		sdrr->type = header->type;
3849 
3850 		rec = ipmi_sdr_get_record(intf, header, sdr_list_itr);
3851 		if (rec == NULL) {
3852 			if (sdrr != NULL) {
3853 				free(sdrr);
3854 				sdrr = NULL;
3855 			}
3856 			continue;
3857 		}
3858 
3859 		switch (header->type) {
3860 		case SDR_RECORD_TYPE_FULL_SENSOR:
3861 			sdrr->record.full =
3862 			    (struct sdr_record_full_sensor *) rec;
3863 			if (!strncmp(
3864 			    (const char *)sdrr->record.full->id_string,
3865 			    (const char *)id,
3866 			    __max(sdrr->record.full->id_code & 0x1f, idlen)))
3867 				found = 1;
3868 			break;
3869 		case SDR_RECORD_TYPE_COMPACT_SENSOR:
3870 			sdrr->record.compact =
3871 			    (struct sdr_record_compact_sensor *) rec;
3872 			if (!strncmp(
3873 			    (const char *)sdrr->record.compact->id_string,
3874 			    (const char *)id,
3875 			    __max(sdrr->record.compact->id_code & 0x1f,
3876 				   idlen)))
3877 				found = 1;
3878 			break;
3879 		case SDR_RECORD_TYPE_EVENTONLY_SENSOR:
3880 			sdrr->record.eventonly =
3881 			    (struct sdr_record_eventonly_sensor *) rec;
3882 			if (!strncmp(
3883 			    (const char *)sdrr->record.eventonly->id_string,
3884 			    (const char *)id,
3885 			    __max(sdrr->record.eventonly->id_code & 0x1f,
3886 				   idlen)))
3887 				found = 1;
3888 			break;
3889 		case SDR_RECORD_TYPE_GENERIC_DEVICE_LOCATOR:
3890 			sdrr->record.genloc =
3891 			    (struct sdr_record_generic_locator *) rec;
3892 			if (!strncmp(
3893 			    (const char *)sdrr->record.genloc->id_string,
3894 			    (const char *)id,
3895 			    __max(sdrr->record.genloc->id_code & 0x1f, idlen)))
3896 				found = 1;
3897 			break;
3898 		case SDR_RECORD_TYPE_FRU_DEVICE_LOCATOR:
3899 			sdrr->record.fruloc =
3900 			    (struct sdr_record_fru_locator *) rec;
3901 			if (!strncmp(
3902 			    (const char *)sdrr->record.fruloc->id_string,
3903 			    (const char *)id,
3904 			    __max(sdrr->record.fruloc->id_code & 0x1f, idlen)))
3905 				found = 1;
3906 			break;
3907 		case SDR_RECORD_TYPE_MC_DEVICE_LOCATOR:
3908 			sdrr->record.mcloc =
3909 			    (struct sdr_record_mc_locator *) rec;
3910 			if (!strncmp(
3911 			    (const char *)sdrr->record.mcloc->id_string,
3912 			    (const char *)id,
3913 			    __max(sdrr->record.mcloc->id_code & 0x1f, idlen)))
3914 				found = 1;
3915 			break;
3916 		case SDR_RECORD_TYPE_ENTITY_ASSOC:
3917 			sdrr->record.entassoc =
3918 			    (struct sdr_record_entity_assoc *) rec;
3919 			break;
3920 		default:
3921 			free(rec);
3922 			rec = NULL;
3923 			if (sdrr != NULL) {
3924 				free(sdrr);
3925 				sdrr = NULL;
3926 			}
3927 			continue;
3928 		}
3929 
3930 		/* add to global record liset */
3931 		if (sdr_list_head == NULL)
3932 			sdr_list_head = sdrr;
3933 		else
3934 			sdr_list_tail->next = sdrr;
3935 
3936 		sdr_list_tail = sdrr;
3937 
3938 		if (found)
3939 			return sdrr;
3940 	}
3941 
3942 	return NULL;
3943 }
3944 
3945 /* ipmi_sdr_list_cache_fromfile  -  generate SDR cache for fast lookup from local file
3946  *
3947  * @intf:	ipmi interface
3948  * @ifile:	input filename
3949  *
3950  * returns pointer to SDR list
3951  * returns NULL on error
3952  */
3953 int
3954 ipmi_sdr_list_cache_fromfile(struct ipmi_intf *intf, const char *ifile)
3955 {
3956 	FILE *fp;
3957 	struct __sdr_header {
3958 		uint16_t id;
3959 		uint8_t version;
3960 		uint8_t type;
3961 		uint8_t length;
3962 	} header;
3963 	struct sdr_record_list *sdrr;
3964 	uint8_t *rec;
3965 	int ret = 0, count = 0, bc = 0;
3966 
3967 	if (ifile == NULL) {
3968 		lprintf(LOG_ERR, "No SDR cache filename given");
3969 		return -1;
3970 	}
3971 
3972 	fp = ipmi_open_file_read(ifile);
3973 	if (fp == NULL) {
3974 		lprintf(LOG_ERR, "Unable to open SDR cache %s for reading",
3975 			ifile);
3976 		return -1;
3977 	}
3978 
3979 	while (feof(fp) == 0) {
3980 		memset(&header, 0, 5);
3981 		bc = fread(&header, 1, 5, fp);
3982 		if (bc <= 0)
3983 			break;
3984 
3985 		if (bc != 5) {
3986 			lprintf(LOG_ERR, "header read %d bytes, expected 5",
3987 				bc);
3988 			ret = -1;
3989 			break;
3990 		}
3991 
3992 		if (header.length == 0)
3993 			continue;
3994 
3995 		if (header.version != 0x51 &&
3996 		    header.version != 0x01 &&
3997 		    header.version != 0x02) {
3998 			lprintf(LOG_WARN, "invalid sdr header version %02x",
3999 				header.version);
4000 			ret = -1;
4001 			break;
4002 		}
4003 
4004 		sdrr = malloc(sizeof (struct sdr_record_list));
4005 		if (sdrr == NULL) {
4006 			lprintf(LOG_ERR, "ipmitool: malloc failure");
4007 			ret = -1;
4008 			break;
4009 		}
4010 		memset(sdrr, 0, sizeof (struct sdr_record_list));
4011 
4012 		sdrr->id = header.id;
4013 		sdrr->type = header.type;
4014 
4015 		rec = malloc(header.length + 1);
4016 		if (rec == NULL) {
4017 			lprintf(LOG_ERR, "ipmitool: malloc failure");
4018 			ret = -1;
4019 			if (sdrr != NULL) {
4020 				free(sdrr);
4021 				sdrr = NULL;
4022 			}
4023 			break;
4024 		}
4025 		memset(rec, 0, header.length + 1);
4026 
4027 		bc = fread(rec, 1, header.length, fp);
4028 		if (bc != header.length) {
4029 			lprintf(LOG_ERR,
4030 				"record %04x read %d bytes, expected %d",
4031 				header.id, bc, header.length);
4032 			ret = -1;
4033 			if (sdrr != NULL) {
4034 				free(sdrr);
4035 				sdrr = NULL;
4036 			}
4037 			if (rec != NULL) {
4038 				free(rec);
4039 				rec = NULL;
4040 			}
4041 			break;
4042 		}
4043 
4044 		switch (header.type) {
4045 		case SDR_RECORD_TYPE_FULL_SENSOR:
4046 		case SDR_RECORD_TYPE_COMPACT_SENSOR:
4047 			sdrr->record.common =
4048 			    (struct sdr_record_common_sensor *) rec;
4049 			break;
4050 		case SDR_RECORD_TYPE_EVENTONLY_SENSOR:
4051 			sdrr->record.eventonly =
4052 			    (struct sdr_record_eventonly_sensor *) rec;
4053 			break;
4054 		case SDR_RECORD_TYPE_GENERIC_DEVICE_LOCATOR:
4055 			sdrr->record.genloc =
4056 			    (struct sdr_record_generic_locator *) rec;
4057 			break;
4058 		case SDR_RECORD_TYPE_FRU_DEVICE_LOCATOR:
4059 			sdrr->record.fruloc =
4060 			    (struct sdr_record_fru_locator *) rec;
4061 			break;
4062 		case SDR_RECORD_TYPE_MC_DEVICE_LOCATOR:
4063 			sdrr->record.mcloc =
4064 			    (struct sdr_record_mc_locator *) rec;
4065 			break;
4066 		case SDR_RECORD_TYPE_ENTITY_ASSOC:
4067 			sdrr->record.entassoc =
4068 			    (struct sdr_record_entity_assoc *) rec;
4069 			break;
4070 		default:
4071 			free(rec);
4072 			rec = NULL;
4073 			if (sdrr != NULL) {
4074 				free(sdrr);
4075 				sdrr = NULL;
4076 			}
4077 			continue;
4078 		}
4079 
4080 		/* add to global record liset */
4081 		if (sdr_list_head == NULL)
4082 			sdr_list_head = sdrr;
4083 		else
4084 			sdr_list_tail->next = sdrr;
4085 
4086 		sdr_list_tail = sdrr;
4087 
4088 		count++;
4089 
4090 		lprintf(LOG_DEBUG, "Read record %04x from file into cache",
4091 			sdrr->id);
4092 	}
4093 
4094 	if (sdr_list_itr == NULL) {
4095 		sdr_list_itr = malloc(sizeof (struct ipmi_sdr_iterator));
4096 		if (sdr_list_itr != NULL) {
4097 			sdr_list_itr->reservation = 0;
4098 			sdr_list_itr->total = count;
4099 			sdr_list_itr->next = 0xffff;
4100 		}
4101 	}
4102 
4103 	fclose(fp);
4104 	return ret;
4105 }
4106 
4107 /* ipmi_sdr_list_cache  -  generate SDR cache for fast lookup
4108  *
4109  * @intf:	ipmi interface
4110  *
4111  * returns pointer to SDR list
4112  * returns NULL on error
4113  */
4114 int
4115 ipmi_sdr_list_cache(struct ipmi_intf *intf)
4116 {
4117 	struct sdr_get_rs *header;
4118 
4119 	if (sdr_list_itr == NULL) {
4120 		sdr_list_itr = ipmi_sdr_start(intf, 0);
4121 		if (sdr_list_itr == NULL) {
4122 			lprintf(LOG_ERR, "Unable to open SDR for reading");
4123 			return -1;
4124 		}
4125 	}
4126 
4127 	while ((header = ipmi_sdr_get_next_header(intf, sdr_list_itr)) != NULL) {
4128 		uint8_t *rec;
4129 		struct sdr_record_list *sdrr;
4130 
4131 		sdrr = malloc(sizeof (struct sdr_record_list));
4132 		if (sdrr == NULL) {
4133 			lprintf(LOG_ERR, "ipmitool: malloc failure");
4134 			break;
4135 		}
4136 		memset(sdrr, 0, sizeof (struct sdr_record_list));
4137 		sdrr->id = header->id;
4138 		sdrr->type = header->type;
4139 
4140 		rec = ipmi_sdr_get_record(intf, header, sdr_list_itr);
4141 		if (rec == NULL) {
4142 			if (sdrr != NULL) {
4143 				free(sdrr);
4144 				sdrr = NULL;
4145 			}
4146 			continue;
4147 		}
4148 
4149 		switch (header->type) {
4150 		case SDR_RECORD_TYPE_FULL_SENSOR:
4151 		case SDR_RECORD_TYPE_COMPACT_SENSOR:
4152 			sdrr->record.common =
4153 			    (struct sdr_record_common_sensor *) rec;
4154 			break;
4155 		case SDR_RECORD_TYPE_EVENTONLY_SENSOR:
4156 			sdrr->record.eventonly =
4157 			    (struct sdr_record_eventonly_sensor *) rec;
4158 			break;
4159 		case SDR_RECORD_TYPE_GENERIC_DEVICE_LOCATOR:
4160 			sdrr->record.genloc =
4161 			    (struct sdr_record_generic_locator *) rec;
4162 			break;
4163 		case SDR_RECORD_TYPE_FRU_DEVICE_LOCATOR:
4164 			sdrr->record.fruloc =
4165 			    (struct sdr_record_fru_locator *) rec;
4166 			break;
4167 		case SDR_RECORD_TYPE_MC_DEVICE_LOCATOR:
4168 			sdrr->record.mcloc =
4169 			    (struct sdr_record_mc_locator *) rec;
4170 			break;
4171 		case SDR_RECORD_TYPE_ENTITY_ASSOC:
4172 			sdrr->record.entassoc =
4173 			    (struct sdr_record_entity_assoc *) rec;
4174 			break;
4175 		default:
4176 			free(rec);
4177 			rec = NULL;
4178 			if (sdrr != NULL) {
4179 				free(sdrr);
4180 				sdrr = NULL;
4181 			}
4182 			continue;
4183 		}
4184 
4185 		/* add to global record liset */
4186 		if (sdr_list_head == NULL)
4187 			sdr_list_head = sdrr;
4188 		else
4189 			sdr_list_tail->next = sdrr;
4190 
4191 		sdr_list_tail = sdrr;
4192 	}
4193 
4194 	return 0;
4195 }
4196 
4197 /*
4198  * ipmi_sdr_get_info
4199  *
4200  * Execute the GET SDR REPOSITORY INFO command, and populate the sdr_info
4201  * structure.
4202  * See section 33.9 of the IPMI v2 specification for details
4203  *
4204  * returns 0 on success
4205  *         -1 on transport error
4206  *         > 0 for other errors
4207  */
4208 int
4209 ipmi_sdr_get_info(struct ipmi_intf *intf,
4210 		  struct get_sdr_repository_info_rsp *sdr_repository_info)
4211 {
4212 	struct ipmi_rs *rsp;
4213 	struct ipmi_rq req;
4214 
4215 	memset(&req, 0, sizeof (req));
4216 
4217 	req.msg.netfn = IPMI_NETFN_STORAGE;	// 0x0A
4218 	req.msg.cmd = IPMI_GET_SDR_REPOSITORY_INFO;	// 0x20
4219 	req.msg.data = 0;
4220 	req.msg.data_len = 0;
4221 
4222 	rsp = intf->sendrecv(intf, &req);
4223 
4224 	if (rsp == NULL) {
4225 		lprintf(LOG_ERR, "Get SDR Repository Info command failed");
4226 		return -1;
4227 	}
4228 	if (rsp->ccode > 0) {
4229 		lprintf(LOG_ERR, "Get SDR Repository Info command failed: %s",
4230 			val2str(rsp->ccode, completion_code_vals));
4231 		return -1;
4232 	}
4233 
4234 	memcpy(sdr_repository_info,
4235 	       rsp->data,
4236 	       __min(sizeof (struct get_sdr_repository_info_rsp),
4237 		     rsp->data_len));
4238 
4239 	return 0;
4240 }
4241 
4242 /* ipmi_sdr_timestamp  -  return string from timestamp value
4243  *
4244  * @stamp:	32bit timestamp
4245  *
4246  * returns pointer to static buffer
4247  */
4248 static char *
4249 ipmi_sdr_timestamp(uint32_t stamp)
4250 {
4251 	static char tbuf[40];
4252 	time_t s = (time_t) stamp;
4253 	memset(tbuf, 0, 40);
4254 	if (stamp)
4255 		strftime(tbuf, sizeof (tbuf), "%m/%d/%Y %H:%M:%S",
4256 			 gmtime(&s));
4257 	return tbuf;
4258 }
4259 
4260 /*
4261  * ipmi_sdr_print_info
4262  *
4263  * Display the return data of the GET SDR REPOSITORY INFO command
4264  * See section 33.9 of the IPMI v2 specification for details
4265  *
4266  * returns 0 on success
4267  *         -1 on error
4268  */
4269 int
4270 ipmi_sdr_print_info(struct ipmi_intf *intf)
4271 {
4272 	uint32_t timestamp;
4273 	uint16_t free_space;
4274 
4275 	struct get_sdr_repository_info_rsp sdr_repository_info;
4276 
4277 	if (ipmi_sdr_get_info(intf, &sdr_repository_info) != 0)
4278 		return -1;
4279 
4280 	printf("SDR Version                         : 0x%x\n",
4281 	       sdr_repository_info.sdr_version);
4282 	printf("Record Count                        : %d\n",
4283 	       (sdr_repository_info.record_count_msb << 8) |
4284 	       sdr_repository_info.record_count_lsb);
4285 
4286 	free_space =
4287 	    (sdr_repository_info.free_space[1] << 8) |
4288 	    sdr_repository_info.free_space[0];
4289 
4290 	printf("Free Space                          : ");
4291 	switch (free_space) {
4292 	case 0x0000:
4293 		printf("none (full)\n");
4294 		break;
4295 	case 0xFFFF:
4296 		printf("unspecified\n");
4297 		break;
4298 	case 0xFFFE:
4299 		printf("> 64Kb - 2 bytes\n");
4300 		break;
4301 	default:
4302 		printf("%d bytes\n", free_space);
4303 		break;
4304 	}
4305 
4306 	timestamp =
4307 	    (sdr_repository_info.most_recent_addition_timestamp[3] << 24) |
4308 	    (sdr_repository_info.most_recent_addition_timestamp[2] << 16) |
4309 	    (sdr_repository_info.most_recent_addition_timestamp[1] << 8) |
4310 	    sdr_repository_info.most_recent_addition_timestamp[0];
4311 	printf("Most recent Addition                : %s\n",
4312 	       ipmi_sdr_timestamp(timestamp));
4313 
4314 	timestamp =
4315 	    (sdr_repository_info.most_recent_erase_timestamp[3] << 24) |
4316 	    (sdr_repository_info.most_recent_erase_timestamp[2] << 16) |
4317 	    (sdr_repository_info.most_recent_erase_timestamp[1] << 8) |
4318 	    sdr_repository_info.most_recent_erase_timestamp[0];
4319 	printf("Most recent Erase                   : %s\n",
4320 	       ipmi_sdr_timestamp(timestamp));
4321 
4322 	printf("SDR overflow                        : %s\n",
4323 	       (sdr_repository_info.overflow_flag ? "yes" : "no"));
4324 
4325 	printf("SDR Repository Update Support       : ");
4326 	switch (sdr_repository_info.modal_update_support) {
4327 	case 0:
4328 		printf("unspecified\n");
4329 		break;
4330 	case 1:
4331 		printf("non-modal\n");
4332 		break;
4333 	case 2:
4334 		printf("modal\n");
4335 		break;
4336 	case 3:
4337 		printf("modal and non-modal\n");
4338 		break;
4339 	default:
4340 		printf("error in response\n");
4341 		break;
4342 	}
4343 
4344 	printf("Delete SDR supported                : %s\n",
4345 	       sdr_repository_info.delete_sdr_supported ? "yes" : "no");
4346 	printf("Partial Add SDR supported           : %s\n",
4347 	       sdr_repository_info.partial_add_sdr_supported ? "yes" : "no");
4348 	printf("Reserve SDR repository supported    : %s\n",
4349 	       sdr_repository_info.
4350 	       reserve_sdr_repository_supported ? "yes" : "no");
4351 	printf("SDR Repository Alloc info supported : %s\n",
4352 	       sdr_repository_info.
4353 				 get_sdr_repository_allo_info_supported ? "yes" : "no");
4354 
4355 	return 0;
4356 }
4357 
4358 /* ipmi_sdr_dump_bin  -  Write raw SDR to binary file
4359  *
4360  * used for post-processing by other utilities
4361  *
4362  * @intf:	ipmi interface
4363  * @ofile:	output filename
4364  *
4365  * returns 0 on success
4366  * returns -1 on error
4367  */
4368 static int
4369 ipmi_sdr_dump_bin(struct ipmi_intf *intf, const char *ofile)
4370 {
4371 	struct sdr_get_rs *header;
4372 	struct ipmi_sdr_iterator *itr;
4373 	struct sdr_record_list *sdrr;
4374 	FILE *fp;
4375 	int rc = 0;
4376 
4377 	/* open connection to SDR */
4378 	itr = ipmi_sdr_start(intf, 0);
4379 	if (itr == NULL) {
4380 		lprintf(LOG_ERR, "Unable to open SDR for reading");
4381 		return -1;
4382 	}
4383 
4384 	printf("Dumping Sensor Data Repository to '%s'\n", ofile);
4385 
4386 	/* generate list of records */
4387 	while ((header = ipmi_sdr_get_next_header(intf, itr)) != NULL) {
4388 		sdrr = malloc(sizeof(struct sdr_record_list));
4389 		if (sdrr == NULL) {
4390 			lprintf(LOG_ERR, "ipmitool: malloc failure");
4391 			return -1;
4392 		}
4393 		memset(sdrr, 0, sizeof(struct sdr_record_list));
4394 
4395 		lprintf(LOG_INFO, "Record ID %04x (%d bytes)",
4396 			header->id, header->length);
4397 
4398 		sdrr->id = header->id;
4399 		sdrr->version = header->version;
4400 		sdrr->type = header->type;
4401 		sdrr->length = header->length;
4402 		sdrr->raw = ipmi_sdr_get_record(intf, header, itr);
4403 
4404 		if (sdrr->raw == NULL) {
4405 		    lprintf(LOG_ERR, "ipmitool: cannot obtain SDR record %04x", header->id);
4406 				if (sdrr != NULL) {
4407 					free(sdrr);
4408 					sdrr = NULL;
4409 				}
4410 		    return -1;
4411 		}
4412 
4413 		if (sdr_list_head == NULL)
4414 			sdr_list_head = sdrr;
4415 		else
4416 			sdr_list_tail->next = sdrr;
4417 
4418 		sdr_list_tail = sdrr;
4419 	}
4420 
4421 	ipmi_sdr_end(intf, itr);
4422 
4423 	/* now write to file */
4424 	fp = ipmi_open_file_write(ofile);
4425 	if (fp == NULL)
4426 		return -1;
4427 
4428 	for (sdrr = sdr_list_head; sdrr != NULL; sdrr = sdrr->next) {
4429 		int r;
4430 		uint8_t h[5];
4431 
4432 		/* build and write sdr header */
4433 		h[0] = sdrr->id & 0xff;   // LS Byte first
4434 		h[1] = (sdrr->id >> 8) & 0xff;
4435 		h[2] = sdrr->version;
4436 		h[3] = sdrr->type;
4437 		h[4] = sdrr->length;
4438 
4439 		r = fwrite(h, 1, 5, fp);
4440 		if (r != 5) {
4441 			lprintf(LOG_ERR, "Error writing header "
4442 				"to output file %s", ofile);
4443 			rc = -1;
4444 			break;
4445 		}
4446 
4447 		/* write sdr entry */
4448 		if (!sdrr->raw) {
4449 			lprintf(LOG_ERR, "Error: raw data is null (length=%d)",
4450 								sdrr->length);
4451 			rc = -1;
4452 			break;
4453 		}
4454 		r = fwrite(sdrr->raw, 1, sdrr->length, fp);
4455 		if (r != sdrr->length) {
4456 			lprintf(LOG_ERR, "Error writing %d record bytes "
4457 				"to output file %s", sdrr->length, ofile);
4458 			rc = -1;
4459 			break;
4460 		}
4461 	}
4462 	fclose(fp);
4463 
4464 	return rc;
4465 }
4466 
4467 /* ipmi_sdr_print_type  -  print all sensors of specified type
4468  *
4469  * @intf:	ipmi interface
4470  * @type:	sensor type
4471  *
4472  * returns 0 on success
4473  * returns -1 on error
4474  */
4475 int
4476 ipmi_sdr_print_type(struct ipmi_intf *intf, char *type)
4477 {
4478 	struct sdr_record_list *list, *entry;
4479 	int rc = 0;
4480 	int x;
4481 	uint8_t sensor_type = 0;
4482 
4483 	if (type == NULL ||
4484 	    strncasecmp(type, "help", 4) == 0 ||
4485 	    strncasecmp(type, "list", 4) == 0) {
4486 		printf("Sensor Types:\n");
4487 		for (x = 1; x < SENSOR_TYPE_MAX; x += 2) {
4488 			printf("\t%-25s (0x%02x)   %-25s (0x%02x)\n",
4489 				sensor_type_desc[x], x,
4490 				sensor_type_desc[x + 1], x + 1);
4491 		}
4492 		return 0;
4493 	}
4494 
4495 	if (strncmp(type, "0x", 2) == 0) {
4496 		/* begins with 0x so let it be entered as raw hex value */
4497 		if (str2uchar(type, &sensor_type) != 0) {
4498 			lprintf(LOG_ERR,
4499 					"Given type of sensor \"%s\" is either invalid or out of range.",
4500 					type);
4501 			return (-1);
4502 		}
4503 	} else {
4504 		for (x = 1; x < SENSOR_TYPE_MAX; x++) {
4505 			if (strncasecmp(sensor_type_desc[x], type,
4506 					__maxlen(type,
4507 						 sensor_type_desc[x])) == 0) {
4508 				sensor_type = x;
4509 				break;
4510 			}
4511 		}
4512 		if (sensor_type != x) {
4513 			lprintf(LOG_ERR, "Sensor Type \"%s\" not found.",
4514 				type);
4515 			printf("Sensor Types:\n");
4516 			for (x = 1; x < SENSOR_TYPE_MAX; x += 2) {
4517 				printf("\t%-25s (0x%02x)   %-25s (0x%02x)\n",
4518 					sensor_type_desc[x], x,
4519 					sensor_type_desc[x + 1], x + 1);
4520 			}
4521 			return 0;
4522 		}
4523 	}
4524 
4525 	list = ipmi_sdr_find_sdr_bysensortype(intf, sensor_type);
4526 
4527 	for (entry = list; entry != NULL; entry = entry->next) {
4528 		rc = ipmi_sdr_print_listentry(intf, entry);
4529 	}
4530 
4531 	__sdr_list_empty(list);
4532 
4533 	return rc;
4534 }
4535 
4536 /* ipmi_sdr_print_entity  -  print entity's for an id/instance
4537  *
4538  * @intf:	ipmi interface
4539  * @entitystr:	entity id/instance string, i.e. "1.1"
4540  *
4541  * returns 0 on success
4542  * returns -1 on error
4543  */
4544 int
4545 ipmi_sdr_print_entity(struct ipmi_intf *intf, char *entitystr)
4546 {
4547 	struct sdr_record_list *list, *entry;
4548 	struct entity_id entity;
4549 	unsigned id = 0;
4550 	unsigned instance = 0;
4551 	int rc = 0;
4552 
4553 	if (entitystr == NULL ||
4554 	    strncasecmp(entitystr, "help", 4) == 0 ||
4555 	    strncasecmp(entitystr, "list", 4) == 0) {
4556 		print_valstr_2col(entity_id_vals, "Entity IDs", -1);
4557 		return 0;
4558 	}
4559 
4560 	if (sscanf(entitystr, "%u.%u", &id, &instance) != 2) {
4561 		/* perhaps no instance was passed
4562 		 * in which case we want all instances for this entity
4563 		 * so set entity.instance = 0x7f to indicate this
4564 		 */
4565 		if (sscanf(entitystr, "%u", &id) != 1) {
4566 			int i, j=0;
4567 
4568 			/* now try string input */
4569 			for (i = 0; entity_id_vals[i].str != NULL; i++) {
4570 				if (strncasecmp(entitystr, entity_id_vals[i].str,
4571 						__maxlen(entitystr, entity_id_vals[i].str)) == 0) {
4572 					entity.id = entity_id_vals[i].val;
4573 					entity.instance = 0x7f;
4574 					j=1;
4575 				}
4576 			}
4577 			if (j == 0) {
4578 				lprintf(LOG_ERR, "Invalid entity: %s", entitystr);
4579 				return -1;
4580 			}
4581 		} else {
4582 			entity.id = id;
4583 			entity.instance = 0x7f;
4584 		}
4585 	} else {
4586 		entity.id = id;
4587 		entity.instance = instance;
4588 	}
4589 
4590 	list = ipmi_sdr_find_sdr_byentity(intf, &entity);
4591 
4592 	for (entry = list; entry != NULL; entry = entry->next) {
4593 		rc = ipmi_sdr_print_listentry(intf, entry);
4594 	}
4595 
4596 	__sdr_list_empty(list);
4597 
4598 	return rc;
4599 }
4600 
4601 /* ipmi_sdr_print_entry_byid  -  print sdr entries identified by sensor id
4602  *
4603  * @intf:	ipmi interface
4604  * @argc:	number of entries to print
4605  * @argv:	list of sensor ids
4606  *
4607  * returns 0 on success
4608  * returns -1 on error
4609  */
4610 static int
4611 ipmi_sdr_print_entry_byid(struct ipmi_intf *intf, int argc, char **argv)
4612 {
4613 	struct sdr_record_list *sdr;
4614 	int rc = 0;
4615 	int v, i;
4616 
4617 	if (argc < 1) {
4618 		lprintf(LOG_ERR, "No Sensor ID supplied");
4619 		return -1;
4620 	}
4621 
4622 	v = verbose;
4623 	verbose = 1;
4624 
4625 	for (i = 0; i < argc; i++) {
4626 		sdr = ipmi_sdr_find_sdr_byid(intf, argv[i]);
4627 		if (sdr == NULL) {
4628 			lprintf(LOG_ERR, "Unable to find sensor id '%s'",
4629 				argv[i]);
4630 		} else {
4631 			if (ipmi_sdr_print_listentry(intf, sdr) < 0)
4632 				rc = -1;
4633 		}
4634 	}
4635 
4636 	verbose = v;
4637 
4638 	return rc;
4639 }
4640 
4641 /* ipmi_sdr_main  -  top-level handler for SDR subsystem
4642  *
4643  * @intf:	ipmi interface
4644  * @argc:	number of arguments
4645  * @argv:	argument list
4646  *
4647  * returns 0 on success
4648  * returns -1 on error
4649  */
4650 int
4651 ipmi_sdr_main(struct ipmi_intf *intf, int argc, char **argv)
4652 {
4653 	int rc = 0;
4654 
4655 	/* initialize random numbers used later */
4656 	srand(time(NULL));
4657 
4658 	if (argc == 0)
4659 		return ipmi_sdr_print_sdr(intf, 0xfe);
4660 	else if (strncmp(argv[0], "help", 4) == 0) {
4661 		printf_sdr_usage();
4662 	} else if (strncmp(argv[0], "list", 4) == 0
4663 		   || strncmp(argv[0], "elist", 5) == 0) {
4664 
4665 		if (strncmp(argv[0], "elist", 5) == 0)
4666 			sdr_extended = 1;
4667 		else
4668 			sdr_extended = 0;
4669 
4670 		if (argc <= 1)
4671 			rc = ipmi_sdr_print_sdr(intf, 0xfe);
4672 		else if (strncmp(argv[1], "all", 3) == 0)
4673 			rc = ipmi_sdr_print_sdr(intf, 0xff);
4674 		else if (strncmp(argv[1], "full", 4) == 0)
4675 			rc = ipmi_sdr_print_sdr(intf,
4676 						SDR_RECORD_TYPE_FULL_SENSOR);
4677 		else if (strncmp(argv[1], "compact", 7) == 0)
4678 			rc = ipmi_sdr_print_sdr(intf,
4679 						SDR_RECORD_TYPE_COMPACT_SENSOR);
4680 		else if (strncmp(argv[1], "event", 5) == 0)
4681 			rc = ipmi_sdr_print_sdr(intf,
4682 						SDR_RECORD_TYPE_EVENTONLY_SENSOR);
4683 		else if (strncmp(argv[1], "mcloc", 5) == 0)
4684 			rc = ipmi_sdr_print_sdr(intf,
4685 						SDR_RECORD_TYPE_MC_DEVICE_LOCATOR);
4686 		else if (strncmp(argv[1], "fru", 3) == 0)
4687 			rc = ipmi_sdr_print_sdr(intf,
4688 						SDR_RECORD_TYPE_FRU_DEVICE_LOCATOR);
4689 		else if (strncmp(argv[1], "generic", 7) == 0)
4690 			rc = ipmi_sdr_print_sdr(intf,
4691 						SDR_RECORD_TYPE_GENERIC_DEVICE_LOCATOR);
4692 		else if (strcmp(argv[1], "help") == 0) {
4693 			lprintf(LOG_NOTICE,
4694 				"usage: sdr %s [all|full|compact|event|mcloc|fru|generic]",
4695 				argv[0]);
4696 			return 0;
4697 		}
4698 		else {
4699 			lprintf(LOG_ERR,
4700 				"Invalid SDR %s command: %s",
4701 				argv[0], argv[1]);
4702 			lprintf(LOG_NOTICE,
4703 				"usage: sdr %s [all|full|compact|event|mcloc|fru|generic]",
4704 				argv[0]);
4705 			return (-1);
4706 		}
4707 	} else if (strncmp(argv[0], "type", 4) == 0) {
4708 		sdr_extended = 1;
4709 		rc = ipmi_sdr_print_type(intf, argv[1]);
4710 	} else if (strncmp(argv[0], "entity", 6) == 0) {
4711 		sdr_extended = 1;
4712 		rc = ipmi_sdr_print_entity(intf, argv[1]);
4713 	} else if (strncmp(argv[0], "info", 4) == 0) {
4714 		rc = ipmi_sdr_print_info(intf);
4715 	} else if (strncmp(argv[0], "get", 3) == 0) {
4716 		rc = ipmi_sdr_print_entry_byid(intf, argc - 1, &argv[1]);
4717 	} else if (strncmp(argv[0], "dump", 4) == 0) {
4718 		if (argc < 2) {
4719 			lprintf(LOG_ERR, "Not enough parameters given.");
4720 			lprintf(LOG_NOTICE, "usage: sdr dump <file>");
4721 			return (-1);
4722 		}
4723 		rc = ipmi_sdr_dump_bin(intf, argv[1]);
4724 	} else if (strncmp(argv[0], "fill", 4) == 0) {
4725 		if (argc <= 1) {
4726 			lprintf(LOG_ERR, "Not enough parameters given.");
4727 			lprintf(LOG_NOTICE, "usage: sdr fill sensors");
4728 			lprintf(LOG_NOTICE, "usage: sdr fill file <file>");
4729 			lprintf(LOG_NOTICE, "usage: sdr fill range <range>");
4730 			return (-1);
4731 		} else if (strncmp(argv[1], "sensors", 7) == 0) {
4732 			rc = ipmi_sdr_add_from_sensors(intf, 21);
4733 		} else if (strncmp(argv[1], "nosat", 5) == 0) {
4734 			rc = ipmi_sdr_add_from_sensors(intf, 0);
4735 		} else if (strncmp(argv[1], "file", 4) == 0) {
4736 			if (argc < 3) {
4737 				lprintf(LOG_ERR,
4738 					"Not enough parameters given.");
4739 				lprintf(LOG_NOTICE,
4740 					"usage: sdr fill file <file>");
4741 				return (-1);
4742 			}
4743 			rc = ipmi_sdr_add_from_file(intf, argv[2]);
4744 		} else if (strncmp(argv[1], "range", 4) == 0) {
4745 			if (argc < 3) {
4746 				lprintf(LOG_ERR,
4747 					"Not enough parameters given.");
4748 				lprintf(LOG_NOTICE,
4749 					"usage: sdr fill range <range>");
4750 				return (-1);
4751 			}
4752 			rc = ipmi_sdr_add_from_list(intf, argv[2]);
4753 		} else {
4754 		    lprintf(LOG_ERR,
4755 			    "Invalid SDR %s command: %s",
4756 			    argv[0], argv[1]);
4757 		    lprintf(LOG_NOTICE,
4758 			    "usage: sdr %s <sensors|nosat|file|range> [options]",
4759 			    argv[0]);
4760 		    return (-1);
4761 		}
4762 	} else {
4763 		lprintf(LOG_ERR, "Invalid SDR command: %s", argv[0]);
4764 		rc = -1;
4765 	}
4766 
4767 	return rc;
4768 }
4769 
4770 void
4771 printf_sdr_usage()
4772 {
4773 	lprintf(LOG_NOTICE,
4774 "usage: sdr <command> [options]");
4775 	lprintf(LOG_NOTICE,
4776 "               list | elist [option]");
4777 	lprintf(LOG_NOTICE,
4778 "                     all           All SDR Records");
4779 	lprintf(LOG_NOTICE,
4780 "                     full          Full Sensor Record");
4781 	lprintf(LOG_NOTICE,
4782 "                     compact       Compact Sensor Record");
4783 	lprintf(LOG_NOTICE,
4784 "                     event         Event-Only Sensor Record");
4785 	lprintf(LOG_NOTICE,
4786 "                     mcloc         Management Controller Locator Record");
4787 	lprintf(LOG_NOTICE,
4788 "                     fru           FRU Locator Record");
4789 	lprintf(LOG_NOTICE,
4790 "                     generic       Generic Device Locator Record\n");
4791 	lprintf(LOG_NOTICE,
4792 "               type [option]");
4793 	lprintf(LOG_NOTICE,
4794 "                     <Sensor_Type> Retrieve the state of specified sensor.");
4795 	lprintf(LOG_NOTICE,
4796 "                                   Sensor_Type can be specified either as");
4797 	lprintf(LOG_NOTICE,
4798 "                                   a string or a hex value.");
4799 	lprintf(LOG_NOTICE,
4800 "                     list          Get a list of available sensor types\n");
4801 	lprintf(LOG_NOTICE,
4802 "               get <Sensor_ID>");
4803 	lprintf(LOG_NOTICE,
4804 "                     Retrieve state of the first sensor matched by Sensor_ID\n");
4805 	lprintf(LOG_NOTICE,
4806 "               info");
4807 	lprintf(LOG_NOTICE,
4808 "                     Display information about the repository itself\n");
4809 	lprintf(LOG_NOTICE,
4810 "               entity <Entity_ID>[.<Instance_ID>]");
4811 	lprintf(LOG_NOTICE,
4812 "                     Display all sensors associated with an entity\n");
4813 	lprintf(LOG_NOTICE,
4814 "               dump <file>");
4815 	lprintf(LOG_NOTICE,
4816 "                     Dump raw SDR data to a file\n");
4817 	lprintf(LOG_NOTICE,
4818 "               fill <option>");
4819 	lprintf(LOG_NOTICE,
4820 "                     sensors       Creates the SDR repository for the current");
4821 	lprintf(LOG_NOTICE,
4822 "                                   configuration");
4823 	lprintf(LOG_NOTICE,
4824 "                     nosat         Creates the SDR repository for the current");
4825 	lprintf(LOG_NOTICE,
4826 "                                   configuration, without satellite scan");
4827 	lprintf(LOG_NOTICE,
4828 "                     file <file>   Load SDR repository from a file");
4829 	lprintf(LOG_NOTICE,
4830 "                     range <range> Load SDR repository from a provided list");
4831 	lprintf(LOG_NOTICE,
4832 "                                   or range. Use ',' for list or '-' for");
4833 	lprintf(LOG_NOTICE,
4834 "                                   range, eg. 0x28,0x32,0x40-0x44");
4835 }
4836