xref: /openbmc/ipmitool/lib/ipmi_sensor.c (revision 89e9e634)
1 /*
2  * Copyright (c) 2003 Sun Microsystems, Inc.  All Rights Reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  *
8  * Redistribution of source code must retain the above copyright
9  * notice, this list of conditions and the following disclaimer.
10  *
11  * Redistribution in binary form must reproduce the above copyright
12  * notice, this list of conditions and the following disclaimer in the
13  * documentation and/or other materials provided with the distribution.
14  *
15  * Neither the name of Sun Microsystems, Inc. or the names of
16  * contributors may be used to endorse or promote products derived
17  * from this software without specific prior written permission.
18  *
19  * This software is provided "AS IS," without a warranty of any kind.
20  * ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES,
21  * INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A
22  * PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED.
23  * SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL NOT BE LIABLE
24  * FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING
25  * OR DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES.  IN NO EVENT WILL
26  * SUN OR ITS LICENSORS BE LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA,
27  * OR FOR DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL OR
28  * PUNITIVE DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY OF
29  * LIABILITY, ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE,
30  * EVEN IF SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
31  */
32 
33 #include <string.h>
34 #include <math.h>
35 
36 #include <ipmitool/ipmi.h>
37 #include <ipmitool/helper.h>
38 #include <ipmitool/log.h>
39 #include <ipmitool/ipmi_intf.h>
40 #include <ipmitool/ipmi_sdr.h>
41 #include <ipmitool/ipmi_sel.h>
42 #include <ipmitool/ipmi_sensor.h>
43 
44 extern int verbose;
45 void print_sensor_get_usage();
46 void print_sensor_thresh_usage();
47 
48 // Macro's for Reading the current sensor Data.
49 #define SCANNING_DISABLED	0x40
50 #define READING_UNAVAILABLE	0x20
51 #define	INVALID_THRESHOLD	"Invalid Threshold data values. Cannot Set Threshold Data."
52 // static
53 int
54 ipmi_sensor_get_sensor_reading_factors(
55 	struct ipmi_intf * intf,
56 	struct sdr_record_full_sensor * sensor,
57 	uint8_t reading)
58 {
59 	struct ipmi_rq req;
60 	struct ipmi_rs * rsp;
61 	uint8_t req_data[2];
62 
63 	char id[17];
64 
65 	if (intf == NULL || sensor == NULL)
66 		return -1;
67 
68 	memset(id, 0, sizeof(id));
69 	memcpy(id, sensor->id_string, 16);
70 
71 	req_data[0] = sensor->cmn.keys.sensor_num;
72 	req_data[1] = reading;
73 
74 	memset(&req, 0, sizeof(req));
75 	req.msg.netfn = IPMI_NETFN_SE;
76 	req.msg.lun = sensor->cmn.keys.lun;
77 	req.msg.cmd   = GET_SENSOR_FACTORS;
78 	req.msg.data  = req_data;
79 	req.msg.data_len = sizeof(req_data);
80 
81 	rsp = intf->sendrecv(intf, &req);
82 
83 	if (rsp == NULL) {
84 		lprintf(LOG_ERR, "Error updating reading factor for sensor %s (#%02x)",
85 			id, sensor->cmn.keys.sensor_num);
86 		return -1;
87 	} else if (rsp->ccode) {
88 		return -1;
89 	} else {
90 		/* Update SDR copy with updated Reading Factors for this reading */
91 		/* Note:
92 		 * The Format of the returned data is exactly as in the SDR definition (Little Endian Format),
93 		 * therefore we can use raw copy operation here.
94 		 * Note: rsp->data[0] would point to the next valid entry in the sampling table
95 		 */
96 		 // BUGBUG: uses 'hardcoded' length information from SDR Definition
97 		memcpy(&sensor->mtol, &rsp->data[1], sizeof(sensor->mtol));
98 		memcpy(&sensor->bacc, &rsp->data[3], sizeof(sensor->bacc));
99 		return 0;
100 	}
101 
102 }
103 
104 static
105 struct ipmi_rs *
106 ipmi_sensor_set_sensor_thresholds(struct ipmi_intf *intf,
107 				  uint8_t sensor,
108 				  uint8_t threshold, uint8_t setting,
109 				  uint8_t target, uint8_t lun, uint8_t channel)
110 {
111 	struct ipmi_rq req;
112 	static struct sensor_set_thresh_rq set_thresh_rq;
113 	struct ipmi_rs *rsp;
114 	uint8_t  bridged_request = 0;
115 	uint32_t save_addr;
116 	uint32_t save_channel;
117 
118 	memset(&set_thresh_rq, 0, sizeof (set_thresh_rq));
119 	set_thresh_rq.sensor_num = sensor;
120 	set_thresh_rq.set_mask = threshold;
121 	if (threshold == UPPER_NON_RECOV_SPECIFIED)
122 		set_thresh_rq.upper_non_recov = setting;
123 	else if (threshold == UPPER_CRIT_SPECIFIED)
124 		set_thresh_rq.upper_crit = setting;
125 	else if (threshold == UPPER_NON_CRIT_SPECIFIED)
126 		set_thresh_rq.upper_non_crit = setting;
127 	else if (threshold == LOWER_NON_CRIT_SPECIFIED)
128 		set_thresh_rq.lower_non_crit = setting;
129 	else if (threshold == LOWER_CRIT_SPECIFIED)
130 		set_thresh_rq.lower_crit = setting;
131 	else if (threshold == LOWER_NON_RECOV_SPECIFIED)
132 		set_thresh_rq.lower_non_recov = setting;
133 	else
134 		return NULL;
135 
136 	if (BRIDGE_TO_SENSOR(intf, target, channel)) {
137 		bridged_request = 1;
138 		save_addr = intf->target_addr;
139 		intf->target_addr = target;
140 		save_channel = intf->target_channel;
141 		intf->target_channel = channel;
142 	}
143 	memset(&req, 0, sizeof (req));
144 	req.msg.netfn = IPMI_NETFN_SE;
145 	req.msg.lun = lun;
146 	req.msg.cmd = SET_SENSOR_THRESHOLDS;
147 	req.msg.data = (uint8_t *) & set_thresh_rq;
148 	req.msg.data_len = sizeof (set_thresh_rq);
149 
150 	rsp = intf->sendrecv(intf, &req);
151 	if (bridged_request) {
152 		intf->target_addr = save_addr;
153 		intf->target_channel = save_channel;
154 	}
155 	return rsp;
156 }
157 
158 static int
159 ipmi_sensor_print_fc_discrete(struct ipmi_intf *intf,
160 				struct sdr_record_common_sensor *sensor,
161 				uint8_t sdr_record_type)
162 {
163 	struct sensor_reading *sr;
164 
165 	sr = ipmi_sdr_read_sensor_value(intf, sensor, sdr_record_type, 3);
166 
167 	if (sr == NULL) {
168 		return -1;
169 	}
170 
171 	if (csv_output) {
172 		/* NOT IMPLEMENTED */
173 	} else {
174 		if (verbose == 0) {
175 			/* output format
176 			 *   id value units status thresholds....
177 			 */
178 			printf("%-16s ", sr->s_id);
179 			if (sr->s_reading_valid) {
180 				if (sr->s_has_analog_value) {
181 					/* don't show discrete component */
182 					printf("| %-10s | %-10s | %-6s",
183 					       sr->s_a_str, sr->s_a_units, "ok");
184 				} else {
185 					printf("| 0x%-8x | %-10s | 0x%02x%02x",
186 					       sr->s_reading, "discrete",
187 					       sr->s_data2, sr->s_data3);
188 				}
189 			} else {
190 				printf("| %-10s | %-10s | %-6s",
191 				       "na", "discrete", "na");
192 			}
193 			printf("| %-10s| %-10s| %-10s| %-10s| %-10s| %-10s",
194 			       "na", "na", "na", "na", "na", "na");
195 
196 			printf("\n");
197 		} else {
198 			printf("Sensor ID              : %s (0x%x)\n",
199 			       sr->s_id, sensor->keys.sensor_num);
200 			printf(" Entity ID             : %d.%d\n",
201 			       sensor->entity.id, sensor->entity.instance);
202 			printf(" Sensor Type (Discrete): %s\n",
203 			       ipmi_sdr_get_sensor_type_desc(sensor->sensor.
204 							     type));
205 			if( sr->s_reading_valid )
206 			{
207 				if (sr->s_has_analog_value) {
208 					printf(" Sensor Reading        : %s %s\n", sr->s_a_str, sr->s_a_units);
209 				}
210 				ipmi_sdr_print_discrete_state("States Asserted",
211 							sensor->sensor.type,
212 							sensor->event_type,
213 							sr->s_data2,
214 							sr->s_data3);
215 				printf("\n");
216 			} else {
217 			   printf(" Unable to read sensor: Device Not Present\n\n");
218 			}
219 	   }
220 	}
221 
222 	return (sr->s_reading_valid ? 0 : -1 );
223 }
224 
225 static void
226 print_thresh_setting(struct sdr_record_full_sensor *full,
227 			 uint8_t thresh_is_avail, uint8_t setting,
228 			 const char *field_sep,
229 			 const char *analog_fmt,
230 			 const char *discrete_fmt,
231 			 const char *na_fmt)
232 {
233 	printf("%s", field_sep);
234 	if (!thresh_is_avail) {
235 		printf(na_fmt, "na");
236 		return;
237 	}
238 	if (full && !UNITS_ARE_DISCRETE(&full->cmn)) {
239 		printf(analog_fmt, sdr_convert_sensor_reading (full, setting));
240 	} else {
241 		printf(discrete_fmt, setting);
242 	}
243 }
244 
245 static int
246 ipmi_sensor_print_fc_threshold(struct ipmi_intf *intf,
247 			      struct sdr_record_common_sensor *sensor,
248 			      uint8_t sdr_record_type)
249 {
250 	int thresh_available = 1;
251 	struct ipmi_rs *rsp;
252 	struct sensor_reading *sr;
253 
254 	sr = ipmi_sdr_read_sensor_value(intf, sensor, sdr_record_type, 3);
255 
256 	if (sr == NULL) {
257 		return -1;
258 	}
259 
260 	const char *thresh_status = ipmi_sdr_get_thresh_status(sr, "ns");
261 
262 	/*
263 	 * Get sensor thresholds
264 	 */
265 	rsp = ipmi_sdr_get_sensor_thresholds(intf,
266 				sensor->keys.sensor_num, sensor->keys.owner_id,
267 				sensor->keys.lun, sensor->keys.channel);
268 
269 	if ((rsp == NULL) || (rsp->ccode > 0) || (rsp->data_len == 0))
270 		thresh_available = 0;
271 
272 	if (csv_output) {
273 		/* NOT IMPLEMENTED */
274 	} else {
275 		if (verbose == 0) {
276 			/* output format
277 			 *   id value units status thresholds....
278 			 */
279 			printf("%-16s ", sr->s_id);
280 			if (sr->s_reading_valid) {
281 				if (sr->s_has_analog_value)
282 					printf("| %-10.3f | %-10s | %-6s",
283 					       sr->s_a_val, sr->s_a_units, thresh_status);
284 				else
285 					printf("| 0x%-8x | %-10s | %-6s",
286 					       sr->s_reading, sr->s_a_units, thresh_status);
287 			} else {
288 				printf("| %-10s | %-10s | %-6s",
289 				       "na", sr->s_a_units, "na");
290 			}
291 			if (thresh_available && sr->full) {
292 #define PTS(bit, dataidx) {						\
293 	print_thresh_setting(sr->full, rsp->data[0] & (bit),  		\
294 	    rsp->data[(dataidx)], "| ", "%-10.3f", "0x-8x", "%-10s");	\
295 }
296 				PTS(LOWER_NON_RECOV_SPECIFIED,	3);
297 				PTS(LOWER_CRIT_SPECIFIED,	2);
298 				PTS(LOWER_NON_CRIT_SPECIFIED,	1);
299 				PTS(UPPER_NON_CRIT_SPECIFIED,	4);
300 				PTS(UPPER_CRIT_SPECIFIED,	5);
301 				PTS(UPPER_NON_RECOV_SPECIFIED,	6);
302 #undef PTS
303 			} else {
304 				printf
305 				    ("| %-10s| %-10s| %-10s| %-10s| %-10s| %-10s",
306 				     "na", "na", "na", "na", "na", "na");
307 			}
308 
309 			printf("\n");
310 		} else {
311 			printf("Sensor ID              : %s (0x%x)\n",
312 			       sr->s_id, sensor->keys.sensor_num);
313 
314 			printf(" Entity ID             : %d.%d\n",
315 			       sensor->entity.id, sensor->entity.instance);
316 
317 			printf(" Sensor Type (Threshold)  : %s\n",
318 			       ipmi_sdr_get_sensor_type_desc(sensor->sensor.
319 							     type));
320 
321 			printf(" Sensor Reading        : ");
322 			if (sr->s_reading_valid) {
323 				if (sr->full) {
324 					uint16_t raw_tol = __TO_TOL(sr->full->mtol);
325 					if (sr->s_has_analog_value) {
326 						double tol =
327 						    sdr_convert_sensor_tolerance(sr->full,
328 									       raw_tol);
329 						printf("%.*f (+/- %.*f) %s\n",
330 						       (sr->s_a_val == (int)
331 						       sr->s_a_val) ? 0 : 3,
332 						       sr->s_a_val,
333 						       (tol == (int) tol) ? 0 : 3, tol,
334 						       sr->s_a_units);
335 					} else {
336 						printf("0x%x (+/- 0x%x) %s\n",
337 						       sr->s_reading,
338 						       raw_tol,
339 						       sr->s_a_units);
340 					}
341 				} else {
342 					printf("0x%x %s\n", sr->s_reading,
343 					sr->s_a_units);
344 				}
345 				printf(" Status                : %s\n", thresh_status);
346 
347 				if (thresh_available) {
348 					if (sr->full) {
349 #define PTS(bit, dataidx, str) { 			\
350 print_thresh_setting(sr->full, rsp->data[0] & (bit),	\
351 		     rsp->data[(dataidx)], 		\
352 		    (str), "%.3f\n", "0x%x\n", "%s\n"); \
353 }
354 
355 						PTS(LOWER_NON_RECOV_SPECIFIED,	3, " Lower Non-Recoverable : ");
356 						PTS(LOWER_CRIT_SPECIFIED,	2, " Lower Critical        : ");
357 						PTS(LOWER_NON_CRIT_SPECIFIED,	1, " Lower Non-Critical    : ");
358 						PTS(UPPER_NON_CRIT_SPECIFIED,	4, " Upper Non-Critical    : ");
359 						PTS(UPPER_CRIT_SPECIFIED,	5, " Upper Critical        : ");
360 						PTS(UPPER_NON_RECOV_SPECIFIED,	6, " Upper Non-Recoverable : ");
361 #undef PTS
362 
363 					}
364 					ipmi_sdr_print_sensor_hysteresis(sensor, sr->full,
365 						sr->full ?  sr->full->threshold.hysteresis.positive :
366 						sr->compact->threshold.hysteresis.positive,
367 						"Positive Hysteresis");
368 
369 					ipmi_sdr_print_sensor_hysteresis(sensor, sr->full,
370 						sr->full ?  sr->full->threshold.hysteresis.negative :
371 						sr->compact->threshold.hysteresis.negative,
372 						"Negative Hysteresis");
373 				} else {
374 					printf(" Sensor Threshold Settings not available\n");
375 				}
376 			} else {
377 			  printf(" Unable to read sensor: Device Not Present\n\n");
378 			}
379 
380 			ipmi_sdr_print_sensor_event_status(intf,
381 							   sensor->keys.
382 							   sensor_num,
383 							   sensor->sensor.type,
384 							   sensor->event_type,
385 							   ANALOG_SENSOR,
386 							   sensor->keys.owner_id,
387 							   sensor->keys.lun,
388 							   sensor->keys.channel);
389 			ipmi_sdr_print_sensor_event_enable(intf,
390 							   sensor->keys.
391 							   sensor_num,
392 							   sensor->sensor.type,
393 							   sensor->event_type,
394 							   ANALOG_SENSOR,
395 							   sensor->keys.owner_id,
396 							   sensor->keys.lun,
397 							   sensor->keys.channel);
398 
399 			printf("\n");
400 		}
401 	}
402 
403 	return (sr->s_reading_valid ? 0 : -1 );
404 }
405 
406 int
407 ipmi_sensor_print_fc(struct ipmi_intf *intf,
408 		       struct sdr_record_common_sensor *sensor,
409 			uint8_t sdr_record_type)
410 {
411 	if (IS_THRESHOLD_SENSOR(sensor))
412 		return ipmi_sensor_print_fc_threshold(intf, sensor, sdr_record_type);
413 	else
414 		return ipmi_sensor_print_fc_discrete(intf, sensor, sdr_record_type);
415 }
416 
417 static int
418 ipmi_sensor_list(struct ipmi_intf *intf)
419 {
420 	struct sdr_get_rs *header;
421 	struct ipmi_sdr_iterator *itr;
422 	int rc = 0;
423 
424 	lprintf(LOG_DEBUG, "Querying SDR for sensor list");
425 
426 	itr = ipmi_sdr_start(intf, 0);
427 	if (itr == NULL) {
428 		lprintf(LOG_ERR, "Unable to open SDR for reading");
429 		return -1;
430 	}
431 
432 	while ((header = ipmi_sdr_get_next_header(intf, itr)) != NULL) {
433 		uint8_t *rec;
434 
435 		rec = ipmi_sdr_get_record(intf, header, itr);
436 		if (rec == NULL) {
437 			lprintf(LOG_DEBUG, "rec == NULL");
438 			continue;
439 		}
440 
441 		switch (header->type) {
442 		case SDR_RECORD_TYPE_FULL_SENSOR:
443 		case SDR_RECORD_TYPE_COMPACT_SENSOR:
444 			ipmi_sensor_print_fc(intf,
445 						   (struct
446 						    sdr_record_common_sensor *)
447 						   rec,
448 						   header->type);
449 			break;
450 		}
451 		free(rec);
452 		rec = NULL;
453 
454 		/* fix for CR6604909: */
455 		/* mask failure of individual reads in sensor list command */
456 		/* rc = (r == 0) ? rc : r; */
457 	}
458 
459 	ipmi_sdr_end(intf, itr);
460 
461 	return rc;
462 }
463 
464 static const struct valstr threshold_vals[] = {
465 	{UPPER_NON_RECOV_SPECIFIED, "Upper Non-Recoverable"},
466 	{UPPER_CRIT_SPECIFIED, "Upper Critical"},
467 	{UPPER_NON_CRIT_SPECIFIED, "Upper Non-Critical"},
468 	{LOWER_NON_RECOV_SPECIFIED, "Lower Non-Recoverable"},
469 	{LOWER_CRIT_SPECIFIED, "Lower Critical"},
470 	{LOWER_NON_CRIT_SPECIFIED, "Lower Non-Critical"},
471 	{0x00, NULL},
472 };
473 
474 static int
475 __ipmi_sensor_set_threshold(struct ipmi_intf *intf,
476 			    uint8_t num, uint8_t mask, uint8_t setting,
477 			    uint8_t target, uint8_t lun, uint8_t channel)
478 {
479 	struct ipmi_rs *rsp;
480 
481 	rsp = ipmi_sensor_set_sensor_thresholds(intf, num, mask, setting,
482 				  target, lun, channel);
483 
484 	if (rsp == NULL) {
485 		lprintf(LOG_ERR, "Error setting threshold");
486 		return -1;
487 	}
488 	if (rsp->ccode > 0) {
489 		lprintf(LOG_ERR, "Error setting threshold: %s",
490 			val2str(rsp->ccode, completion_code_vals));
491 		return -1;
492 	}
493 
494 	return 0;
495 }
496 
497 static uint8_t
498 __ipmi_sensor_threshold_value_to_raw(struct sdr_record_full_sensor *full, double value)
499 {
500 	if (!UNITS_ARE_DISCRETE(&full->cmn)) { /* Has an analog reading */
501 		/* Has an analog reading and supports mx+b */
502 		return sdr_convert_sensor_value_to_raw(full, value);
503 	}
504 	else {
505 		/* Does not have an analog reading and/or does not support mx+b */
506 		if (value > 255) {
507 			return 255;
508 		}
509 		else if (value < 0) {
510 			return 0;
511 		}
512 		else {
513 			return (uint8_t )value;
514 		}
515 	}
516 }
517 
518 static int
519 ipmi_sensor_set_threshold(struct ipmi_intf *intf, int argc, char **argv)
520 {
521 	char *id, *thresh;
522 	uint8_t settingMask = 0;
523 	double setting1 = 0.0, setting2 = 0.0, setting3 = 0.0;
524 	int allUpper = 0, allLower = 0;
525 	int ret = 0;
526 	struct ipmi_rs *rsp;
527 	int i =0;
528 	double val[10] = {0};
529 
530 	struct sdr_record_list *sdr;
531 
532 	if (argc < 3 || strncmp(argv[0], "help", 4) == 0) {
533 		print_sensor_thresh_usage();
534 		return 0;
535 	}
536 
537 	id = argv[0];
538 	thresh = argv[1];
539 
540 	if (strncmp(thresh, "upper", 5) == 0) {
541 		if (argc < 5) {
542 			lprintf(LOG_ERR,
543 				"usage: sensor thresh <id> upper <unc> <ucr> <unr>");
544 			return -1;
545 		}
546 		allUpper = 1;
547 		if (str2double(argv[2], &setting1) != 0) {
548 			lprintf(LOG_ERR, "Given unc '%s' is invalid.",
549 					argv[2]);
550 			return (-1);
551 		}
552 		if (str2double(argv[3], &setting2) != 0) {
553 			lprintf(LOG_ERR, "Given ucr '%s' is invalid.",
554 					argv[3]);
555 			return (-1);
556 		}
557 		if (str2double(argv[4], &setting3) != 0) {
558 			lprintf(LOG_ERR, "Given unr '%s' is invalid.",
559 					argv[4]);
560 			return (-1);
561 		}
562 	} else if (strncmp(thresh, "lower", 5) == 0) {
563 		if (argc < 5) {
564 			lprintf(LOG_ERR,
565 				"usage: sensor thresh <id> lower <lnr> <lcr> <lnc>");
566 			return -1;
567 		}
568 		allLower = 1;
569 		if (str2double(argv[2], &setting1) != 0) {
570 			lprintf(LOG_ERR, "Given lnc '%s' is invalid.",
571 					argv[2]);
572 			return (-1);
573 		}
574 		if (str2double(argv[3], &setting2) != 0) {
575 			lprintf(LOG_ERR, "Given lcr '%s' is invalid.",
576 					argv[3]);
577 			return (-1);
578 		}
579 		if (str2double(argv[4], &setting3) != 0) {
580 			lprintf(LOG_ERR, "Given lnr '%s' is invalid.",
581 					argv[4]);
582 			return (-1);
583 		}
584 	} else {
585 		if (strncmp(thresh, "unr", 3) == 0)
586 			settingMask = UPPER_NON_RECOV_SPECIFIED;
587 		else if (strncmp(thresh, "ucr", 3) == 0)
588 			settingMask = UPPER_CRIT_SPECIFIED;
589 		else if (strncmp(thresh, "unc", 3) == 0)
590 			settingMask = UPPER_NON_CRIT_SPECIFIED;
591 		else if (strncmp(thresh, "lnc", 3) == 0)
592 			settingMask = LOWER_NON_CRIT_SPECIFIED;
593 		else if (strncmp(thresh, "lcr", 3) == 0)
594 			settingMask = LOWER_CRIT_SPECIFIED;
595 		else if (strncmp(thresh, "lnr", 3) == 0)
596 			settingMask = LOWER_NON_RECOV_SPECIFIED;
597 		else {
598 			lprintf(LOG_ERR,
599 				"Valid threshold '%s' for sensor '%s' not specified!",
600 				thresh, id);
601 			return -1;
602 		}
603 		if (str2double(argv[2], &setting1) != 0) {
604 			lprintf(LOG_ERR,
605 					"Given %s threshold value '%s' is invalid.",
606 					thresh, argv[2]);
607 			return (-1);
608 		}
609 	}
610 
611 	printf("Locating sensor record '%s'...\n", id);
612 
613 	/* lookup by sensor name */
614 	sdr = ipmi_sdr_find_sdr_byid(intf, id);
615 	if (sdr == NULL) {
616 		lprintf(LOG_ERR, "Sensor data record not found!");
617 		return -1;
618 	}
619 
620 	if (sdr->type != SDR_RECORD_TYPE_FULL_SENSOR) {
621 		lprintf(LOG_ERR, "Invalid sensor type %02x", sdr->type);
622 		return -1;
623 	}
624 
625 	if (!IS_THRESHOLD_SENSOR(sdr->record.common)) {
626 		lprintf(LOG_ERR, "Invalid sensor event type %02x", sdr->record.common->event_type);
627 		return -1;
628 	}
629 
630 
631 	if (allUpper) {
632 		settingMask = UPPER_NON_CRIT_SPECIFIED;
633 		printf("Setting sensor \"%s\" %s threshold to %.3f\n",
634 		       sdr->record.full->id_string,
635 		       val2str(settingMask, threshold_vals), setting1);
636 		ret = __ipmi_sensor_set_threshold(intf,
637 						  sdr->record.common->keys.
638 						  sensor_num, settingMask,
639 						  __ipmi_sensor_threshold_value_to_raw(sdr->record.full, setting1),
640 						  sdr->record.common->keys.owner_id,
641 						  sdr->record.common->keys.lun,
642 						  sdr->record.common->keys.channel);
643 
644 		settingMask = UPPER_CRIT_SPECIFIED;
645 		printf("Setting sensor \"%s\" %s threshold to %.3f\n",
646 		       sdr->record.full->id_string,
647 		       val2str(settingMask, threshold_vals), setting2);
648 		ret = __ipmi_sensor_set_threshold(intf,
649 						  sdr->record.common->keys.
650 						  sensor_num, settingMask,
651 						  __ipmi_sensor_threshold_value_to_raw(sdr->record.full, setting2),
652 						  sdr->record.common->keys.owner_id,
653 						  sdr->record.common->keys.lun,
654 						  sdr->record.common->keys.channel);
655 
656 		settingMask = UPPER_NON_RECOV_SPECIFIED;
657 		printf("Setting sensor \"%s\" %s threshold to %.3f\n",
658 		       sdr->record.full->id_string,
659 		       val2str(settingMask, threshold_vals), setting3);
660 		ret = __ipmi_sensor_set_threshold(intf,
661 						  sdr->record.common->keys.
662 						  sensor_num, settingMask,
663 						  __ipmi_sensor_threshold_value_to_raw(sdr->record.full, setting3),
664 						  sdr->record.common->keys.owner_id,
665 						  sdr->record.common->keys.lun,
666 						  sdr->record.common->keys.channel);
667 	} else if (allLower) {
668 		settingMask = LOWER_NON_RECOV_SPECIFIED;
669 		printf("Setting sensor \"%s\" %s threshold to %.3f\n",
670 		       sdr->record.full->id_string,
671 		       val2str(settingMask, threshold_vals), setting1);
672 		ret = __ipmi_sensor_set_threshold(intf,
673 						  sdr->record.common->keys.
674 						  sensor_num, settingMask,
675 						  __ipmi_sensor_threshold_value_to_raw(sdr->record.full, setting1),
676 						  sdr->record.common->keys.owner_id,
677 						  sdr->record.common->keys.lun,
678 						  sdr->record.common->keys.channel);
679 
680 		settingMask = LOWER_CRIT_SPECIFIED;
681 		printf("Setting sensor \"%s\" %s threshold to %.3f\n",
682 		       sdr->record.full->id_string,
683 		       val2str(settingMask, threshold_vals), setting2);
684 		ret = __ipmi_sensor_set_threshold(intf,
685 						  sdr->record.common->keys.
686 						  sensor_num, settingMask,
687 						  __ipmi_sensor_threshold_value_to_raw(sdr->record.full, setting2),
688 						  sdr->record.common->keys.owner_id,
689 						  sdr->record.common->keys.lun,
690 						  sdr->record.common->keys.channel);
691 
692 		settingMask = LOWER_NON_CRIT_SPECIFIED;
693 		printf("Setting sensor \"%s\" %s threshold to %.3f\n",
694 		       sdr->record.full->id_string,
695 		       val2str(settingMask, threshold_vals), setting3);
696 		ret = __ipmi_sensor_set_threshold(intf,
697 						  sdr->record.common->keys.
698 						  sensor_num, settingMask,
699 						  __ipmi_sensor_threshold_value_to_raw(sdr->record.full, setting3),
700 						  sdr->record.common->keys.owner_id,
701 						  sdr->record.common->keys.lun,
702 						  sdr->record.common->keys.channel);
703 	} else {
704 
705 	/*
706  	 * Current implementation doesn't check for the valid setting of upper non critical and other thresholds.
707  	 * In the below logic:
708  	 * 	Get all the current reading of the sensor i.e. unc, uc, lc,lnc.
709  	 * 	Validate the values given by the user.
710  	 * 	If the values are not correct, then popup with the Error message and return.
711  	 */
712 	/*
713 	 * Get current reading
714 	 */
715 		rsp = ipmi_sdr_get_sensor_reading_ipmb(intf,
716 					       sdr->record.common->keys.sensor_num,
717 					       sdr->record.common->keys.owner_id,
718 					       sdr->record.common->keys.lun,sdr->record.common->keys.channel);
719 		rsp = ipmi_sdr_get_sensor_thresholds(intf,
720 						sdr->record.common->keys.sensor_num,
721 						sdr->record.common->keys.owner_id,
722 						sdr->record.common->keys.lun,
723 						sdr->record.common->keys.channel);
724 		if ((rsp == NULL) || (rsp->ccode > 0)) {
725 			lprintf(LOG_ERR, "Sensor data record not found!");
726 				return -1;
727 		}
728 		for(i=1;i<=6;i++) {
729 			val[i] = sdr_convert_sensor_reading(sdr->record.full, rsp->data[i]);
730 			if(val[i] < 0)
731 				val[i] = 0;
732 		}
733 		/* Check for the valid Upper non recovarable Value.*/
734 		if( (settingMask & UPPER_NON_RECOV_SPECIFIED) ) {
735 
736 			if( (rsp->data[0] & UPPER_NON_RECOV_SPECIFIED) &&
737 				(( (rsp->data[0] & UPPER_CRIT_SPECIFIED) && ( setting1 <= val[5])) ||
738 					( (rsp->data[0] & UPPER_NON_CRIT_SPECIFIED) && ( setting1 <= val[4]))) )
739 			{
740 				lprintf(LOG_ERR, INVALID_THRESHOLD);
741 				return -1;
742 			}
743 		} else if( (settingMask & UPPER_CRIT_SPECIFIED) ) { 		/* Check for the valid Upper critical Value.*/
744 			if( (rsp->data[0] & UPPER_CRIT_SPECIFIED) &&
745 				(((rsp->data[0] & UPPER_NON_RECOV_SPECIFIED)&& ( setting1 >= val[6])) ||
746 				((rsp->data[0] & UPPER_NON_CRIT_SPECIFIED)&&( setting1 <= val[4]))) )
747 			{
748 				lprintf(LOG_ERR, INVALID_THRESHOLD);
749 				return -1;
750 			}
751 		} else if( (settingMask & UPPER_NON_CRIT_SPECIFIED) ) {  		/* Check for the valid Upper non critical Value.*/
752 			if( (rsp->data[0] & UPPER_NON_CRIT_SPECIFIED) &&
753 				(((rsp->data[0] & UPPER_NON_RECOV_SPECIFIED)&&( setting1 >= val[6])) ||
754 				((rsp->data[0] & UPPER_CRIT_SPECIFIED)&&( setting1 >= val[5])) ||
755 				((rsp->data[0] & LOWER_NON_CRIT_SPECIFIED)&&( setting1 <= val[1]))) )
756 			{
757 				lprintf(LOG_ERR, INVALID_THRESHOLD);
758 				return -1;
759 			}
760 		} else if( (settingMask & LOWER_NON_CRIT_SPECIFIED) ) {		/* Check for the valid lower non critical Value.*/
761 			if( (rsp->data[0] & LOWER_NON_CRIT_SPECIFIED) &&
762 				(((rsp->data[0] & LOWER_CRIT_SPECIFIED)&&( setting1 <= val[2])) ||
763 				((rsp->data[0] & LOWER_NON_RECOV_SPECIFIED)&&( setting1 <= val[3]))||
764 				((rsp->data[0] & UPPER_NON_CRIT_SPECIFIED)&&( setting1 >= val[4]))) )
765 			{
766 				lprintf(LOG_ERR, INVALID_THRESHOLD);
767 				return -1;
768 			}
769 		} else if( (settingMask & LOWER_CRIT_SPECIFIED) ) {		/* Check for the valid lower critical Value.*/
770 			if( (rsp->data[0] & LOWER_CRIT_SPECIFIED) &&
771 				(((rsp->data[0] & LOWER_NON_CRIT_SPECIFIED)&&( setting1 >= val[1])) ||
772 				((rsp->data[0] & LOWER_NON_RECOV_SPECIFIED)&&( setting1 <= val[3]))) )
773 			{
774 				lprintf(LOG_ERR, INVALID_THRESHOLD);
775 				return -1;
776 			}
777 		} else if( (settingMask & LOWER_NON_RECOV_SPECIFIED) ) {		/* Check for the valid lower non recovarable Value.*/
778 			if( (rsp->data[0] & LOWER_NON_RECOV_SPECIFIED) &&
779 				(((rsp->data[0] & LOWER_NON_CRIT_SPECIFIED)&&( setting1 >= val[1])) ||
780 				((rsp->data[0] & LOWER_CRIT_SPECIFIED)&&( setting1 >= val[2]))) )
781 			{
782 				lprintf(LOG_ERR, INVALID_THRESHOLD);
783 				return -1;
784 			}
785 		} else {			/* None of this Then Return with error messages.*/
786 			lprintf(LOG_ERR, INVALID_THRESHOLD);
787 			return -1;
788 		}
789 
790 
791 		printf("Setting sensor \"%s\" %s threshold to %.3f\n",
792 		       sdr->record.full->id_string,
793 		       val2str(settingMask, threshold_vals), setting1);
794 
795 		ret = __ipmi_sensor_set_threshold(intf,
796 						  sdr->record.common->keys.
797 						  sensor_num, settingMask,
798 						  __ipmi_sensor_threshold_value_to_raw(sdr->record.full, setting1),
799 						  sdr->record.common->keys.owner_id,
800 						  sdr->record.common->keys.lun,
801 						  sdr->record.common->keys.channel);
802 	}
803 
804 	return ret;
805 }
806 
807 static int
808 ipmi_sensor_get_reading(struct ipmi_intf *intf, int argc, char **argv)
809 {
810 	struct sdr_record_list *sdr;
811 	int i, rc=0;
812 
813 	if (argc < 1 || strncmp(argv[0], "help", 4) == 0) {
814 		lprintf(LOG_NOTICE, "sensor reading <id> ... [id]");
815 		lprintf(LOG_NOTICE, "   id        : name of desired sensor");
816 		return -1;
817 	}
818 
819 	for (i = 0; i < argc; i++) {
820 		sdr = ipmi_sdr_find_sdr_byid(intf, argv[i]);
821 		if (sdr == NULL) {
822 			lprintf(LOG_ERR, "Sensor \"%s\" not found!",
823 				argv[i]);
824 			rc = -1;
825 			continue;
826 		}
827 
828 		switch (sdr->type) {
829 		case SDR_RECORD_TYPE_FULL_SENSOR:
830 		case SDR_RECORD_TYPE_COMPACT_SENSOR:
831 		{
832 			struct sensor_reading *sr;
833 			struct sdr_record_common_sensor	*sensor = sdr->record.common;
834 			sr = ipmi_sdr_read_sensor_value(intf, sensor, sdr->type, 3);
835 
836 			if (sr == NULL) {
837 				rc = -1;
838 				continue;
839 			}
840 
841 			if (!sr->full)
842 				continue;
843 
844 			if (!sr->s_reading_valid)
845 				continue;
846 
847 			if (!sr->s_has_analog_value) {
848 				lprintf(LOG_ERR, "Sensor \"%s\" is a discrete sensor!", argv[i]);
849 				continue;
850 			}
851 			if (csv_output)
852 				printf("%s,%s\n", argv[i], sr->s_a_str);
853 			else
854 				printf("%-16s | %s\n", argv[i], sr->s_a_str);
855 
856 			break;
857 		}
858 		default:
859 			continue;
860 		}
861 	}
862 
863 	return rc;
864 }
865 
866 static int
867 ipmi_sensor_get(struct ipmi_intf *intf, int argc, char **argv)
868 {
869 	int i, v;
870 	int rc = 0;
871 	struct sdr_record_list *sdr;
872 
873 	if (argc < 1) {
874 		lprintf(LOG_ERR, "Not enough parameters given.");
875 		print_sensor_get_usage();
876 		return (-1);
877 	} else if (strcmp(argv[0], "help") == 0) {
878 		print_sensor_get_usage();
879 		return 0;
880 	}
881 	printf("Locating sensor record...\n");
882 	/* lookup by sensor name */
883 	for (i = 0; i < argc; i++) {
884 		sdr = ipmi_sdr_find_sdr_byid(intf, argv[i]);
885 		if (sdr == NULL) {
886 			lprintf(LOG_ERR, "Sensor data record \"%s\" not found!",
887 					argv[i]);
888 			rc = -1;
889 			continue;
890 		}
891 		/* need to set verbose level to 1 */
892 		v = verbose;
893 		verbose = 1;
894 		switch (sdr->type) {
895 		case SDR_RECORD_TYPE_FULL_SENSOR:
896 		case SDR_RECORD_TYPE_COMPACT_SENSOR:
897 			if (ipmi_sensor_print_fc(intf,
898 					(struct sdr_record_common_sensor *) sdr->record.common,
899 					sdr->type)) {
900 				rc = -1;
901 			}
902 			break;
903 		default:
904 			if (ipmi_sdr_print_listentry(intf, sdr) < 0) {
905 				rc = (-1);
906 			}
907 			break;
908 		}
909 		verbose = v;
910 		sdr = NULL;
911 	}
912 	return rc;
913 }
914 
915 int
916 ipmi_sensor_main(struct ipmi_intf *intf, int argc, char **argv)
917 {
918 	int rc = 0;
919 
920 	if (argc == 0) {
921 		rc = ipmi_sensor_list(intf);
922 	} else if (strncmp(argv[0], "help", 4) == 0) {
923 		lprintf(LOG_NOTICE, "Sensor Commands:  list thresh get reading");
924 	} else if (strncmp(argv[0], "list", 4) == 0) {
925 		rc = ipmi_sensor_list(intf);
926 	} else if (strncmp(argv[0], "thresh", 5) == 0) {
927 		rc = ipmi_sensor_set_threshold(intf, argc - 1, &argv[1]);
928 	} else if (strncmp(argv[0], "get", 3) == 0) {
929 		rc = ipmi_sensor_get(intf, argc - 1, &argv[1]);
930 	} else if (strncmp(argv[0], "reading", 7) == 0) {
931 		rc = ipmi_sensor_get_reading(intf, argc - 1, &argv[1]);
932 	} else {
933 		lprintf(LOG_ERR, "Invalid sensor command: %s", argv[0]);
934 		rc = -1;
935 	}
936 
937 	return rc;
938 }
939 
940 /* print_sensor_get_usage - print usage for # ipmitool sensor get NAC;
941  *
942  * @returns: void
943  */
944 void
945 print_sensor_get_usage()
946 {
947 	lprintf(LOG_NOTICE, "sensor get <id> ... [id]");
948 	lprintf(LOG_NOTICE, "   id        : name of desired sensor");
949 }
950 
951 /* print_sensor_thresh_set_usage - print usage for # ipmitool sensor thresh;
952  *
953  * @returns: void
954  */
955 void
956 print_sensor_thresh_usage()
957 {
958 	lprintf(LOG_NOTICE,
959 "sensor thresh <id> <threshold> <setting>");
960 	lprintf(LOG_NOTICE,
961 "   id        : name of the sensor for which threshold is to be set");
962 	lprintf(LOG_NOTICE,
963 "   threshold : which threshold to set");
964 	lprintf(LOG_NOTICE,
965 "                 unr = upper non-recoverable");
966 	lprintf(LOG_NOTICE,
967 "                 ucr = upper critical");
968 	lprintf(LOG_NOTICE,
969 "                 unc = upper non-critical");
970 	lprintf(LOG_NOTICE,
971 "                 lnc = lower non-critical");
972 	lprintf(LOG_NOTICE,
973 "                 lcr = lower critical");
974 	lprintf(LOG_NOTICE,
975 "                 lnr = lower non-recoverable");
976 	lprintf(LOG_NOTICE,
977 "   setting   : the value to set the threshold to");
978 	lprintf(LOG_NOTICE,
979 "");
980 	lprintf(LOG_NOTICE,
981 "sensor thresh <id> lower <lnr> <lcr> <lnc>");
982 	lprintf(LOG_NOTICE,
983 "   Set all lower thresholds at the same time");
984 	lprintf(LOG_NOTICE,
985 "");
986 	lprintf(LOG_NOTICE,
987 "sensor thresh <id> upper <unc> <ucr> <unr>");
988 	lprintf(LOG_NOTICE,
989 "   Set all upper thresholds at the same time");
990 	lprintf(LOG_NOTICE, "");
991 }
992