xref: /openbmc/ipmitool/lib/ipmi_sensor.c (revision 6ca88cb6)
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 	const char *id;
164 	struct sensor_reading *sr;
165 
166 	sr = ipmi_sdr_read_sensor_value(intf, sensor, sdr_record_type, 3);
167 
168 	if (sr == NULL) {
169 		return -1;
170 	}
171 
172 	if (csv_output) {
173 		/* NOT IMPLEMENTED */
174 	} else {
175 		if (verbose == 0) {
176 			/* output format
177 			 *   id value units status thresholds....
178 			 */
179 			printf("%-16s ", sr->s_id);
180 			if (sr->s_reading_valid) {
181 				if (sr->s_has_analog_value) {
182 					/* don't show discrete component */
183 					printf("| %-10s | %-10s | %-6s",
184 					       sr->s_a_str, sr->s_a_units, "ok");
185 				} else {
186 					printf("| 0x%-8x | %-10s | 0x%02x%02x",
187 					       sr->s_reading, "discrete",
188 					       sr->s_data2, sr->s_data3);
189 				}
190 			} else {
191 				printf("| %-10s | %-10s | %-6s",
192 				       "na", "discrete", "na");
193 			}
194 			printf("| %-10s| %-10s| %-10s| %-10s| %-10s| %-10s",
195 			       "na", "na", "na", "na", "na", "na");
196 
197 			printf("\n");
198 		} else {
199 			printf("Sensor ID              : %s (0x%x)\n",
200 			       sr->s_id, sensor->keys.sensor_num);
201 			printf(" Entity ID             : %d.%d\n",
202 			       sensor->entity.id, sensor->entity.instance);
203 			printf(" Sensor Type (Discrete): %s\n",
204 			       ipmi_sdr_get_sensor_type_desc(sensor->sensor.
205 							     type));
206 			if( sr->s_reading_valid )
207 			{
208 				if (sr->s_has_analog_value) {
209 					printf(" Sensor Reading        : %s %s\n", sr->s_a_str, sr->s_a_units);
210 				}
211 				ipmi_sdr_print_discrete_state("States Asserted",
212 							sensor->sensor.type,
213 							sensor->event_type,
214 							sr->s_data2,
215 							sr->s_data3);
216 				printf("\n");
217 			} else {
218 			   printf(" Unable to read sensor: Device Not Present\n\n");
219 			}
220 	   }
221 	}
222 
223 	return (sr->s_reading_valid ? 0 : -1 );
224 }
225 
226 static void
227 print_thresh_setting(struct sdr_record_full_sensor *full,
228 			 uint8_t thresh_is_avail, uint8_t setting,
229 			 const char *field_sep,
230 			 const char *analog_fmt,
231 			 const char *discrete_fmt,
232 			 const char *na_fmt)
233 {
234 	printf("%s", field_sep);
235 	if (!thresh_is_avail) {
236 		printf(na_fmt, "na");
237 		return;
238 	}
239 	if (full && !UNITS_ARE_DISCRETE(&full->cmn)) {
240 		printf(analog_fmt, sdr_convert_sensor_reading (full, setting));
241 	} else {
242 		printf(discrete_fmt, setting);
243 	}
244 }
245 
246 static int
247 ipmi_sensor_print_fc_threshold(struct ipmi_intf *intf,
248 			      struct sdr_record_common_sensor *sensor,
249 			      uint8_t sdr_record_type)
250 {
251 	int thresh_available = 1;
252 	struct ipmi_rs *rsp;
253 	struct sensor_reading *sr;
254 
255 	sr = ipmi_sdr_read_sensor_value(intf, sensor, sdr_record_type, 3);
256 
257 	if (sr == NULL) {
258 		return -1;
259 	}
260 
261 	const char *thresh_status = ipmi_sdr_get_thresh_status(sr, "ns");
262 
263 	/*
264 	 * Get sensor thresholds
265 	 */
266 	rsp = ipmi_sdr_get_sensor_thresholds(intf,
267 				sensor->keys.sensor_num, sensor->keys.owner_id,
268 				sensor->keys.lun, sensor->keys.channel);
269 
270 	if ((rsp == NULL) || (rsp->ccode > 0) || (rsp->data_len == 0))
271 		thresh_available = 0;
272 
273 	if (csv_output) {
274 		/* NOT IMPLEMENTED */
275 	} else {
276 		if (verbose == 0) {
277 			/* output format
278 			 *   id value units status thresholds....
279 			 */
280 			printf("%-16s ", sr->s_id);
281 			if (sr->s_reading_valid) {
282 				if (sr->s_has_analog_value)
283 					printf("| %-10.3f | %-10s | %-6s",
284 					       sr->s_a_val, sr->s_a_units, thresh_status);
285 				else
286 					printf("| 0x%-8x | %-10s | %-6s",
287 					       sr->s_reading, sr->s_a_units, thresh_status);
288 			} else {
289 				printf("| %-10s | %-10s | %-6s",
290 				       "na", sr->s_a_units, "na");
291 			}
292 			if (thresh_available && sr->full) {
293 #define PTS(bit, dataidx) {						\
294 	print_thresh_setting(sr->full, rsp->data[0] & (bit),  		\
295 	    rsp->data[(dataidx)], "| ", "%-10.3f", "0x-8x", "%-10s");	\
296 }
297 				PTS(LOWER_NON_RECOV_SPECIFIED,	3);
298 				PTS(LOWER_CRIT_SPECIFIED,	2);
299 				PTS(LOWER_NON_CRIT_SPECIFIED,	1);
300 				PTS(UPPER_NON_CRIT_SPECIFIED,	4);
301 				PTS(UPPER_CRIT_SPECIFIED,	5);
302 				PTS(UPPER_NON_RECOV_SPECIFIED,	6);
303 #undef PTS
304 			} else {
305 				printf
306 				    ("| %-10s| %-10s| %-10s| %-10s| %-10s| %-10s",
307 				     "na", "na", "na", "na", "na", "na");
308 			}
309 
310 			printf("\n");
311 		} else {
312 			printf("Sensor ID              : %s (0x%x)\n",
313 			       sr->s_id, sensor->keys.sensor_num);
314 
315 			printf(" Entity ID             : %d.%d\n",
316 			       sensor->entity.id, sensor->entity.instance);
317 
318 			printf(" Sensor Type (Threshold)  : %s\n",
319 			       ipmi_sdr_get_sensor_type_desc(sensor->sensor.
320 							     type));
321 
322 			printf(" Sensor Reading        : ");
323 			if (sr->s_reading_valid) {
324 				if (sr->full) {
325 					uint16_t raw_tol = __TO_TOL(sr->full->mtol);
326 					if (sr->s_has_analog_value) {
327 						double tol =
328 						    sdr_convert_sensor_tolerance(sr->full,
329 									       raw_tol);
330 						printf("%.*f (+/- %.*f) %s\n",
331 						       (sr->s_a_val == (int)
332 						       sr->s_a_val) ? 0 : 3,
333 						       sr->s_a_val,
334 						       (tol == (int) tol) ? 0 : 3, tol,
335 						       sr->s_a_units);
336 					} else {
337 						printf("0x%x (+/- 0x%x) %s\n",
338 						       sr->s_reading,
339 						       raw_tol,
340 						       sr->s_a_units);
341 					}
342 				} else {
343 					printf("0x%x %s\n", sr->s_reading,
344 					sr->s_a_units);
345 				}
346 				printf(" Status                : %s\n", thresh_status);
347 
348 				if (thresh_available) {
349 					if (sr->full) {
350 #define PTS(bit, dataidx, str) { 			\
351 print_thresh_setting(sr->full, rsp->data[0] & (bit),	\
352 		     rsp->data[(dataidx)], 		\
353 		    (str), "%.3f\n", "0x%x\n", "%s\n"); \
354 }
355 
356 						PTS(LOWER_NON_RECOV_SPECIFIED,	3, " Lower Non-Recoverable : ");
357 						PTS(LOWER_CRIT_SPECIFIED,	2, " Lower Critical        : ");
358 						PTS(LOWER_NON_CRIT_SPECIFIED,	1, " Lower Non-Critical    : ");
359 						PTS(UPPER_NON_CRIT_SPECIFIED,	4, " Upper Non-Critical    : ");
360 						PTS(UPPER_CRIT_SPECIFIED,	5, " Upper Critical        : ");
361 						PTS(UPPER_NON_RECOV_SPECIFIED,	6, " Upper Non-Recoverable : ");
362 #undef PTS
363 
364 					}
365 					ipmi_sdr_print_sensor_hysteresis(sensor, sr->full,
366 						sr->full ?  sr->full->threshold.hysteresis.positive :
367 						sr->compact->threshold.hysteresis.positive,
368 						"Positive Hysteresis");
369 
370 					ipmi_sdr_print_sensor_hysteresis(sensor, sr->full,
371 						sr->full ?  sr->full->threshold.hysteresis.negative :
372 						sr->compact->threshold.hysteresis.negative,
373 						"Negative Hysteresis");
374 				} else {
375 					printf(" Sensor Threshold Settings not available\n");
376 				}
377 			} else {
378 			  printf(" Unable to read sensor: Device Not Present\n\n");
379 			}
380 
381 			ipmi_sdr_print_sensor_event_status(intf,
382 							   sensor->keys.
383 							   sensor_num,
384 							   sensor->sensor.type,
385 							   sensor->event_type,
386 							   ANALOG_SENSOR,
387 							   sensor->keys.owner_id,
388 							   sensor->keys.lun,
389 							   sensor->keys.channel);
390 			ipmi_sdr_print_sensor_event_enable(intf,
391 							   sensor->keys.
392 							   sensor_num,
393 							   sensor->sensor.type,
394 							   sensor->event_type,
395 							   ANALOG_SENSOR,
396 							   sensor->keys.owner_id,
397 							   sensor->keys.lun,
398 							   sensor->keys.channel);
399 
400 			printf("\n");
401 		}
402 	}
403 
404 	return (sr->s_reading_valid ? 0 : -1 );
405 }
406 
407 int
408 ipmi_sensor_print_fc(struct ipmi_intf *intf,
409 		       struct sdr_record_common_sensor *sensor,
410 			uint8_t sdr_record_type)
411 {
412 	if (IS_THRESHOLD_SENSOR(sensor))
413 		return ipmi_sensor_print_fc_threshold(intf, sensor, sdr_record_type);
414 	else
415 		return ipmi_sensor_print_fc_discrete(intf, sensor, sdr_record_type);
416 }
417 
418 static int
419 ipmi_sensor_list(struct ipmi_intf *intf)
420 {
421 	struct sdr_get_rs *header;
422 	struct ipmi_sdr_iterator *itr;
423 	int rc = 0;
424 
425 	lprintf(LOG_DEBUG, "Querying SDR for sensor list");
426 
427 	itr = ipmi_sdr_start(intf, 0);
428 	if (itr == NULL) {
429 		lprintf(LOG_ERR, "Unable to open SDR for reading");
430 		return -1;
431 	}
432 
433 	while ((header = ipmi_sdr_get_next_header(intf, itr)) != NULL) {
434 		uint8_t *rec;
435 
436 		rec = ipmi_sdr_get_record(intf, header, itr);
437 		if (rec == NULL) {
438 			lprintf(LOG_DEBUG, "rec == NULL");
439 			continue;
440 		}
441 
442 		switch (header->type) {
443 		case SDR_RECORD_TYPE_FULL_SENSOR:
444 		case SDR_RECORD_TYPE_COMPACT_SENSOR:
445 			ipmi_sensor_print_fc(intf,
446 						   (struct
447 						    sdr_record_common_sensor *)
448 						   rec,
449 						   header->type);
450 			break;
451 		}
452 		free(rec);
453 		rec = NULL;
454 
455 		/* fix for CR6604909: */
456 		/* mask failure of individual reads in sensor list command */
457 		/* rc = (r == 0) ? rc : r; */
458 	}
459 
460 	ipmi_sdr_end(intf, itr);
461 
462 	return rc;
463 }
464 
465 static const struct valstr threshold_vals[] = {
466 	{UPPER_NON_RECOV_SPECIFIED, "Upper Non-Recoverable"},
467 	{UPPER_CRIT_SPECIFIED, "Upper Critical"},
468 	{UPPER_NON_CRIT_SPECIFIED, "Upper Non-Critical"},
469 	{LOWER_NON_RECOV_SPECIFIED, "Lower Non-Recoverable"},
470 	{LOWER_CRIT_SPECIFIED, "Lower Critical"},
471 	{LOWER_NON_CRIT_SPECIFIED, "Lower Non-Critical"},
472 	{0x00, NULL},
473 };
474 
475 static int
476 __ipmi_sensor_set_threshold(struct ipmi_intf *intf,
477 			    uint8_t num, uint8_t mask, uint8_t setting,
478 			    uint8_t target, uint8_t lun, uint8_t channel)
479 {
480 	struct ipmi_rs *rsp;
481 
482 	rsp = ipmi_sensor_set_sensor_thresholds(intf, num, mask, setting,
483 				  target, lun, channel);
484 
485 	if (rsp == NULL) {
486 		lprintf(LOG_ERR, "Error setting threshold");
487 		return -1;
488 	}
489 	if (rsp->ccode > 0) {
490 		lprintf(LOG_ERR, "Error setting threshold: %s",
491 			val2str(rsp->ccode, completion_code_vals));
492 		return -1;
493 	}
494 
495 	return 0;
496 }
497 
498 static uint8_t
499 __ipmi_sensor_threshold_value_to_raw(struct sdr_record_full_sensor *full, double value)
500 {
501 	if (!UNITS_ARE_DISCRETE(&full->cmn)) { /* Has an analog reading */
502 		/* Has an analog reading and supports mx+b */
503 		return sdr_convert_sensor_value_to_raw(full, value);
504 	}
505 	else {
506 		/* Does not have an analog reading and/or does not support mx+b */
507 		if (value > 255) {
508 			return 255;
509 		}
510 		else if (value < 0) {
511 			return 0;
512 		}
513 		else {
514 			return (uint8_t )value;
515 		}
516 	}
517 }
518 
519 static int
520 ipmi_sensor_set_threshold(struct ipmi_intf *intf, int argc, char **argv)
521 {
522 	char *id, *thresh;
523 	uint8_t settingMask = 0;
524 	double setting1 = 0.0, setting2 = 0.0, setting3 = 0.0;
525 	int allUpper = 0, allLower = 0;
526 	int ret = 0;
527 	struct ipmi_rs *rsp;
528 	int i =0;
529 	double val[10] = {0};
530 
531 	struct sdr_record_list *sdr;
532 
533 	if (argc < 3 || strncmp(argv[0], "help", 4) == 0) {
534 		print_sensor_thresh_usage();
535 		return 0;
536 	}
537 
538 	id = argv[0];
539 	thresh = argv[1];
540 
541 	if (strncmp(thresh, "upper", 5) == 0) {
542 		if (argc < 5) {
543 			lprintf(LOG_ERR,
544 				"usage: sensor thresh <id> upper <unc> <ucr> <unr>");
545 			return -1;
546 		}
547 		allUpper = 1;
548 		if (str2double(argv[2], &setting1) != 0) {
549 			lprintf(LOG_ERR, "Given unc '%s' is invalid.",
550 					argv[2]);
551 			return (-1);
552 		}
553 		if (str2double(argv[3], &setting2) != 0) {
554 			lprintf(LOG_ERR, "Given ucr '%s' is invalid.",
555 					argv[3]);
556 			return (-1);
557 		}
558 		if (str2double(argv[4], &setting3) != 0) {
559 			lprintf(LOG_ERR, "Given unr '%s' is invalid.",
560 					argv[4]);
561 			return (-1);
562 		}
563 	} else if (strncmp(thresh, "lower", 5) == 0) {
564 		if (argc < 5) {
565 			lprintf(LOG_ERR,
566 				"usage: sensor thresh <id> lower <lnr> <lcr> <lnc>");
567 			return -1;
568 		}
569 		allLower = 1;
570 		if (str2double(argv[2], &setting1) != 0) {
571 			lprintf(LOG_ERR, "Given lnc '%s' is invalid.",
572 					argv[2]);
573 			return (-1);
574 		}
575 		if (str2double(argv[3], &setting2) != 0) {
576 			lprintf(LOG_ERR, "Given lcr '%s' is invalid.",
577 					argv[3]);
578 			return (-1);
579 		}
580 		if (str2double(argv[4], &setting3) != 0) {
581 			lprintf(LOG_ERR, "Given lnr '%s' is invalid.",
582 					argv[4]);
583 			return (-1);
584 		}
585 	} else {
586 		if (strncmp(thresh, "unr", 3) == 0)
587 			settingMask = UPPER_NON_RECOV_SPECIFIED;
588 		else if (strncmp(thresh, "ucr", 3) == 0)
589 			settingMask = UPPER_CRIT_SPECIFIED;
590 		else if (strncmp(thresh, "unc", 3) == 0)
591 			settingMask = UPPER_NON_CRIT_SPECIFIED;
592 		else if (strncmp(thresh, "lnc", 3) == 0)
593 			settingMask = LOWER_NON_CRIT_SPECIFIED;
594 		else if (strncmp(thresh, "lcr", 3) == 0)
595 			settingMask = LOWER_CRIT_SPECIFIED;
596 		else if (strncmp(thresh, "lnr", 3) == 0)
597 			settingMask = LOWER_NON_RECOV_SPECIFIED;
598 		else {
599 			lprintf(LOG_ERR,
600 				"Valid threshold '%s' for sensor '%s' not specified!",
601 				thresh, id);
602 			return -1;
603 		}
604 		if (str2double(argv[2], &setting1) != 0) {
605 			lprintf(LOG_ERR,
606 					"Given %s threshold value '%s' is invalid.",
607 					thresh, argv[2]);
608 			return (-1);
609 		}
610 	}
611 
612 	printf("Locating sensor record '%s'...\n", id);
613 
614 	/* lookup by sensor name */
615 	sdr = ipmi_sdr_find_sdr_byid(intf, id);
616 	if (sdr == NULL) {
617 		lprintf(LOG_ERR, "Sensor data record not found!");
618 		return -1;
619 	}
620 
621 	if (sdr->type != SDR_RECORD_TYPE_FULL_SENSOR) {
622 		lprintf(LOG_ERR, "Invalid sensor type %02x", sdr->type);
623 		return -1;
624 	}
625 
626 	if (!IS_THRESHOLD_SENSOR(sdr->record.common)) {
627 		lprintf(LOG_ERR, "Invalid sensor event type %02x", sdr->record.common->event_type);
628 		return -1;
629 	}
630 
631 
632 	if (allUpper) {
633 		settingMask = UPPER_NON_CRIT_SPECIFIED;
634 		printf("Setting sensor \"%s\" %s threshold to %.3f\n",
635 		       sdr->record.full->id_string,
636 		       val2str(settingMask, threshold_vals), setting1);
637 		ret = __ipmi_sensor_set_threshold(intf,
638 						  sdr->record.common->keys.
639 						  sensor_num, settingMask,
640 						  __ipmi_sensor_threshold_value_to_raw(sdr->record.full, setting1),
641 						  sdr->record.common->keys.owner_id,
642 						  sdr->record.common->keys.lun,
643 						  sdr->record.common->keys.channel);
644 
645 		settingMask = UPPER_CRIT_SPECIFIED;
646 		printf("Setting sensor \"%s\" %s threshold to %.3f\n",
647 		       sdr->record.full->id_string,
648 		       val2str(settingMask, threshold_vals), setting2);
649 		ret = __ipmi_sensor_set_threshold(intf,
650 						  sdr->record.common->keys.
651 						  sensor_num, settingMask,
652 						  __ipmi_sensor_threshold_value_to_raw(sdr->record.full, setting2),
653 						  sdr->record.common->keys.owner_id,
654 						  sdr->record.common->keys.lun,
655 						  sdr->record.common->keys.channel);
656 
657 		settingMask = UPPER_NON_RECOV_SPECIFIED;
658 		printf("Setting sensor \"%s\" %s threshold to %.3f\n",
659 		       sdr->record.full->id_string,
660 		       val2str(settingMask, threshold_vals), setting3);
661 		ret = __ipmi_sensor_set_threshold(intf,
662 						  sdr->record.common->keys.
663 						  sensor_num, settingMask,
664 						  __ipmi_sensor_threshold_value_to_raw(sdr->record.full, setting3),
665 						  sdr->record.common->keys.owner_id,
666 						  sdr->record.common->keys.lun,
667 						  sdr->record.common->keys.channel);
668 	} else if (allLower) {
669 		settingMask = LOWER_NON_RECOV_SPECIFIED;
670 		printf("Setting sensor \"%s\" %s threshold to %.3f\n",
671 		       sdr->record.full->id_string,
672 		       val2str(settingMask, threshold_vals), setting1);
673 		ret = __ipmi_sensor_set_threshold(intf,
674 						  sdr->record.common->keys.
675 						  sensor_num, settingMask,
676 						  __ipmi_sensor_threshold_value_to_raw(sdr->record.full, setting1),
677 						  sdr->record.common->keys.owner_id,
678 						  sdr->record.common->keys.lun,
679 						  sdr->record.common->keys.channel);
680 
681 		settingMask = LOWER_CRIT_SPECIFIED;
682 		printf("Setting sensor \"%s\" %s threshold to %.3f\n",
683 		       sdr->record.full->id_string,
684 		       val2str(settingMask, threshold_vals), setting2);
685 		ret = __ipmi_sensor_set_threshold(intf,
686 						  sdr->record.common->keys.
687 						  sensor_num, settingMask,
688 						  __ipmi_sensor_threshold_value_to_raw(sdr->record.full, setting2),
689 						  sdr->record.common->keys.owner_id,
690 						  sdr->record.common->keys.lun,
691 						  sdr->record.common->keys.channel);
692 
693 		settingMask = LOWER_NON_CRIT_SPECIFIED;
694 		printf("Setting sensor \"%s\" %s threshold to %.3f\n",
695 		       sdr->record.full->id_string,
696 		       val2str(settingMask, threshold_vals), setting3);
697 		ret = __ipmi_sensor_set_threshold(intf,
698 						  sdr->record.common->keys.
699 						  sensor_num, settingMask,
700 						  __ipmi_sensor_threshold_value_to_raw(sdr->record.full, setting3),
701 						  sdr->record.common->keys.owner_id,
702 						  sdr->record.common->keys.lun,
703 						  sdr->record.common->keys.channel);
704 	} else {
705 
706 	/*
707  	 * Current implementation doesn't check for the valid setting of upper non critical and other thresholds.
708  	 * In the below logic:
709  	 * 	Get all the current reading of the sensor i.e. unc, uc, lc,lnc.
710  	 * 	Validate the values given by the user.
711  	 * 	If the values are not correct, then popup with the Error message and return.
712  	 */
713 	/*
714 	 * Get current reading
715 	 */
716 		rsp = ipmi_sdr_get_sensor_reading_ipmb(intf,
717 					       sdr->record.common->keys.sensor_num,
718 					       sdr->record.common->keys.owner_id,
719 					       sdr->record.common->keys.lun,sdr->record.common->keys.channel);
720 		rsp = ipmi_sdr_get_sensor_thresholds(intf,
721 						sdr->record.common->keys.sensor_num,
722 						sdr->record.common->keys.owner_id,
723 						sdr->record.common->keys.lun,
724 						sdr->record.common->keys.channel);
725 		if ((rsp == NULL) || (rsp->ccode > 0)) {
726 			lprintf(LOG_ERR, "Sensor data record not found!");
727 				return -1;
728 		}
729 		for(i=1;i<=6;i++) {
730 			val[i] = sdr_convert_sensor_reading(sdr->record.full, rsp->data[i]);
731 			if(val[i] < 0)
732 				val[i] = 0;
733 		}
734 		/* Check for the valid Upper non recovarable Value.*/
735 		if( (settingMask & UPPER_NON_RECOV_SPECIFIED) ) {
736 
737 			if( (rsp->data[0] & UPPER_NON_RECOV_SPECIFIED) &&
738 				(( (rsp->data[0] & UPPER_CRIT_SPECIFIED) && ( setting1 <= val[5])) ||
739 					( (rsp->data[0] & UPPER_NON_CRIT_SPECIFIED) && ( setting1 <= val[4]))) )
740 			{
741 				lprintf(LOG_ERR, INVALID_THRESHOLD);
742 				return -1;
743 			}
744 		} else if( (settingMask & UPPER_CRIT_SPECIFIED) ) { 		/* Check for the valid Upper critical Value.*/
745 			if( (rsp->data[0] & UPPER_CRIT_SPECIFIED) &&
746 				(((rsp->data[0] & UPPER_NON_RECOV_SPECIFIED)&& ( setting1 >= val[6])) ||
747 				((rsp->data[0] & UPPER_NON_CRIT_SPECIFIED)&&( setting1 <= val[4]))) )
748 			{
749 				lprintf(LOG_ERR, INVALID_THRESHOLD);
750 				return -1;
751 			}
752 		} else if( (settingMask & UPPER_NON_CRIT_SPECIFIED) ) {  		/* Check for the valid Upper non critical Value.*/
753 			if( (rsp->data[0] & UPPER_NON_CRIT_SPECIFIED) &&
754 				(((rsp->data[0] & UPPER_NON_RECOV_SPECIFIED)&&( setting1 >= val[6])) ||
755 				((rsp->data[0] & UPPER_CRIT_SPECIFIED)&&( setting1 >= val[5])) ||
756 				((rsp->data[0] & LOWER_NON_CRIT_SPECIFIED)&&( setting1 <= val[1]))) )
757 			{
758 				lprintf(LOG_ERR, INVALID_THRESHOLD);
759 				return -1;
760 			}
761 		} else if( (settingMask & LOWER_NON_CRIT_SPECIFIED) ) {		/* Check for the valid lower non critical Value.*/
762 			if( (rsp->data[0] & LOWER_NON_CRIT_SPECIFIED) &&
763 				(((rsp->data[0] & LOWER_CRIT_SPECIFIED)&&( setting1 <= val[2])) ||
764 				((rsp->data[0] & LOWER_NON_RECOV_SPECIFIED)&&( setting1 <= val[3]))||
765 				((rsp->data[0] & UPPER_NON_CRIT_SPECIFIED)&&( setting1 >= val[4]))) )
766 			{
767 				lprintf(LOG_ERR, INVALID_THRESHOLD);
768 				return -1;
769 			}
770 		} else if( (settingMask & LOWER_CRIT_SPECIFIED) ) {		/* Check for the valid lower critical Value.*/
771 			if( (rsp->data[0] & LOWER_CRIT_SPECIFIED) &&
772 				(((rsp->data[0] & LOWER_NON_CRIT_SPECIFIED)&&( setting1 >= val[1])) ||
773 				((rsp->data[0] & LOWER_NON_RECOV_SPECIFIED)&&( setting1 <= val[3]))) )
774 			{
775 				lprintf(LOG_ERR, INVALID_THRESHOLD);
776 				return -1;
777 			}
778 		} else if( (settingMask & LOWER_NON_RECOV_SPECIFIED) ) {		/* Check for the valid lower non recovarable Value.*/
779 			if( (rsp->data[0] & LOWER_NON_RECOV_SPECIFIED) &&
780 				(((rsp->data[0] & LOWER_NON_CRIT_SPECIFIED)&&( setting1 >= val[1])) ||
781 				((rsp->data[0] & LOWER_CRIT_SPECIFIED)&&( setting1 >= val[2]))) )
782 			{
783 				lprintf(LOG_ERR, INVALID_THRESHOLD);
784 				return -1;
785 			}
786 		} else {			/* None of this Then Return with error messages.*/
787 			lprintf(LOG_ERR, INVALID_THRESHOLD);
788 			return -1;
789 		}
790 
791 
792 		printf("Setting sensor \"%s\" %s threshold to %.3f\n",
793 		       sdr->record.full->id_string,
794 		       val2str(settingMask, threshold_vals), setting1);
795 
796 		ret = __ipmi_sensor_set_threshold(intf,
797 						  sdr->record.common->keys.
798 						  sensor_num, settingMask,
799 						  __ipmi_sensor_threshold_value_to_raw(sdr->record.full, setting1),
800 						  sdr->record.common->keys.owner_id,
801 						  sdr->record.common->keys.lun,
802 						  sdr->record.common->keys.channel);
803 	}
804 
805 	return ret;
806 }
807 
808 static int
809 ipmi_sensor_get_reading(struct ipmi_intf *intf, int argc, char **argv)
810 {
811 	struct sdr_record_list *sdr;
812 	int i, rc=0;
813 
814 	if (argc < 1 || strncmp(argv[0], "help", 4) == 0) {
815 		lprintf(LOG_NOTICE, "sensor reading <id> ... [id]");
816 		lprintf(LOG_NOTICE, "   id        : name of desired sensor");
817 		return -1;
818 	}
819 
820 	for (i = 0; i < argc; i++) {
821 		sdr = ipmi_sdr_find_sdr_byid(intf, argv[i]);
822 		if (sdr == NULL) {
823 			lprintf(LOG_ERR, "Sensor \"%s\" not found!",
824 				argv[i]);
825 			rc = -1;
826 			continue;
827 		}
828 
829 		switch (sdr->type) {
830 		case SDR_RECORD_TYPE_FULL_SENSOR:
831 		case SDR_RECORD_TYPE_COMPACT_SENSOR:
832 		{
833 			struct sensor_reading *sr;
834 			struct sdr_record_common_sensor	*sensor = sdr->record.common;
835 			sr = ipmi_sdr_read_sensor_value(intf, sensor, sdr->type, 3);
836 
837 			if (sr == NULL) {
838 				rc = -1;
839 				continue;
840 			}
841 
842 			if (!sr->full)
843 				continue;
844 
845 			if (!sr->s_reading_valid)
846 				continue;
847 
848 			if (!sr->s_has_analog_value) {
849 				lprintf(LOG_ERR, "Sensor \"%s\" is a discrete sensor!", argv[i]);
850 				continue;
851 			}
852 			if (csv_output)
853 				printf("%s,%s\n", argv[i], sr->s_a_str);
854 			else
855 				printf("%-16s | %s\n", argv[i], sr->s_a_str);
856 
857 			break;
858 		}
859 		default:
860 			continue;
861 		}
862 	}
863 
864 	return rc;
865 }
866 
867 static int
868 ipmi_sensor_get(struct ipmi_intf *intf, int argc, char **argv)
869 {
870 	int i, v;
871 	int rc = 0;
872 	struct sdr_record_list *sdr;
873 
874 	if (argc < 1) {
875 		lprintf(LOG_ERR, "Not enough parameters given.");
876 		print_sensor_get_usage();
877 		return (-1);
878 	} else if (strcmp(argv[0], "help") == 0) {
879 		print_sensor_get_usage();
880 		return 0;
881 	}
882 	printf("Locating sensor record...\n");
883 	/* lookup by sensor name */
884 	for (i = 0; i < argc; i++) {
885 		sdr = ipmi_sdr_find_sdr_byid(intf, argv[i]);
886 		if (sdr == NULL) {
887 			lprintf(LOG_ERR, "Sensor data record \"%s\" not found!",
888 					argv[i]);
889 			rc = -1;
890 			continue;
891 		}
892 		/* need to set verbose level to 1 */
893 		v = verbose;
894 		verbose = 1;
895 		switch (sdr->type) {
896 		case SDR_RECORD_TYPE_FULL_SENSOR:
897 		case SDR_RECORD_TYPE_COMPACT_SENSOR:
898 			if (ipmi_sensor_print_fc(intf,
899 					(struct sdr_record_common_sensor *) sdr->record.common,
900 					sdr->type)) {
901 				rc = -1;
902 			}
903 			break;
904 		default:
905 			if (ipmi_sdr_print_listentry(intf, sdr) < 0) {
906 				rc = (-1);
907 			}
908 			break;
909 		}
910 		verbose = v;
911 		sdr = NULL;
912 	}
913 	return rc;
914 }
915 
916 int
917 ipmi_sensor_main(struct ipmi_intf *intf, int argc, char **argv)
918 {
919 	int rc = 0;
920 
921 	if (argc == 0) {
922 		rc = ipmi_sensor_list(intf);
923 	} else if (strncmp(argv[0], "help", 4) == 0) {
924 		lprintf(LOG_NOTICE, "Sensor Commands:  list thresh get reading");
925 	} else if (strncmp(argv[0], "list", 4) == 0) {
926 		rc = ipmi_sensor_list(intf);
927 	} else if (strncmp(argv[0], "thresh", 5) == 0) {
928 		rc = ipmi_sensor_set_threshold(intf, argc - 1, &argv[1]);
929 	} else if (strncmp(argv[0], "get", 3) == 0) {
930 		rc = ipmi_sensor_get(intf, argc - 1, &argv[1]);
931 	} else if (strncmp(argv[0], "reading", 7) == 0) {
932 		rc = ipmi_sensor_get_reading(intf, argc - 1, &argv[1]);
933 	} else {
934 		lprintf(LOG_ERR, "Invalid sensor command: %s", argv[0]);
935 		rc = -1;
936 	}
937 
938 	return rc;
939 }
940 
941 /* print_sensor_get_usage - print usage for # ipmitool sensor get NAC;
942  *
943  * @returns: void
944  */
945 void
946 print_sensor_get_usage()
947 {
948 	lprintf(LOG_NOTICE, "sensor get <id> ... [id]");
949 	lprintf(LOG_NOTICE, "   id        : name of desired sensor");
950 }
951 
952 /* print_sensor_thresh_set_usage - print usage for # ipmitool sensor thresh;
953  *
954  * @returns: void
955  */
956 void
957 print_sensor_thresh_usage()
958 {
959 	lprintf(LOG_NOTICE,
960 "sensor thresh <id> <threshold> <setting>");
961 	lprintf(LOG_NOTICE,
962 "   id        : name of the sensor for which threshold is to be set");
963 	lprintf(LOG_NOTICE,
964 "   threshold : which threshold to set");
965 	lprintf(LOG_NOTICE,
966 "                 unr = upper non-recoverable");
967 	lprintf(LOG_NOTICE,
968 "                 ucr = upper critical");
969 	lprintf(LOG_NOTICE,
970 "                 unc = upper non-critical");
971 	lprintf(LOG_NOTICE,
972 "                 lnc = lower non-critical");
973 	lprintf(LOG_NOTICE,
974 "                 lcr = lower critical");
975 	lprintf(LOG_NOTICE,
976 "                 lnr = lower non-recoverable");
977 	lprintf(LOG_NOTICE,
978 "   setting   : the value to set the threshold to");
979 	lprintf(LOG_NOTICE,
980 "");
981 	lprintf(LOG_NOTICE,
982 "sensor thresh <id> lower <lnr> <lcr> <lnc>");
983 	lprintf(LOG_NOTICE,
984 "   Set all lower thresholds at the same time");
985 	lprintf(LOG_NOTICE,
986 "");
987 	lprintf(LOG_NOTICE,
988 "sensor thresh <id> upper <unc> <ucr> <unr>");
989 	lprintf(LOG_NOTICE,
990 "   Set all upper thresholds at the same time");
991 	lprintf(LOG_NOTICE, "");
992 }
993