xref: /openbmc/ipmitool/lib/ipmi_dcmi.c (revision d531785a)
1 /*
2  * Copyright (C) 2008 Intel Corporation.
3  * All rights reserved
4  *
5  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
6  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
7  * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
8  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
9  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
10  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
11  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
12  * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
13  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
14  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
15  * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
16  *
17  */
18 
19 /* Theory of operation
20  *
21  * DCMI is the Data Center Management Interface which is a subset of IPMI v2.0.
22  * DCMI incorporates the ability to locate a system with DCMI functionality,
23  * its available temperature sensors, and power limiting control.
24  *
25  * All of the available DCMI commands are contained in a struct with a numeric
26  * value and a string.  When the user specifies a command the string is
27  * compared to one of several structs and is then given a numeric value based
28  * on the matched string.  A case statement is used to select the desired
29  * action from the user.  If an invalid string is entered, or a string that is
30  * not a command option is entered, the available commands are printed to the
31  * screen.  This allows the strings to be changed quickly with the DCMI spec.
32  *
33  * Each called function usually executes whichever command was requested to
34  * keep the main() from being overly complicated.
35  *
36  * This code conforms to the 1.0 DCMI Specification
37  *  released by Hari Ramachandran of the Intel Corporation
38  */
39 
40 #include <stdlib.h>
41 #include <string.h>
42 #include <stdio.h>
43 #include <math.h>
44 #include <unistd.h>
45 #include <sys/types.h>
46 #include <time.h>
47 #include <netdb.h>
48 
49 #include <ipmitool/ipmi_dcmi.h>
50 #include <ipmitool/helper.h>
51 #include <ipmitool/ipmi.h>
52 #include <ipmitool/log.h>
53 #include <ipmitool/ipmi_intf.h>
54 #include <ipmitool/ipmi_strings.h>
55 #include <ipmitool/ipmi_mc.h>
56 #include <ipmitool/ipmi_entity.h>
57 #include <ipmitool/ipmi_constants.h>
58 #include <ipmitool/ipmi_sensor.h>
59 
60 #include "../src/plugins/lanplus/lanplus.h"
61 
62 #define IPMI_LAN_PORT       0x26f
63 
64 extern int verbose;
65 
66 static int ipmi_print_sensor_info(struct ipmi_intf *intf, uint16_t rec_id);
67 
68 /*******************************************************************************
69  * The structs below are the DCMI command option strings.  They are printed    *
70  * when the user does not issue enough options or the wrong ones.  The reason  *
71  * that the DMCI command strings are in a struct is so that when the           *
72  * specification changes, the strings can be changed quickly with out having   *
73  * to change a lot of the code in the main().                                  *
74  ******************************************************************************/
75 
76 /* Main set of DCMI commands */
77 const struct dcmi_cmd dcmi_cmd_vals[] = {
78 	{ 0x00, "discover", "           Used to discover supported DCMI capabilities" },
79 	{ 0x01, "power", "              Platform power limit command options"         },
80 	{ 0x02, "sensors", "            Prints the available DCMI sensors"            },
81 	{ 0x03, "asset_tag", "          Prints the platform's asset tag"              },
82 	{ 0x04, "set_asset_tag", "      Sets the platform's asset tag"                },
83 	{ 0x05, "get_mc_id_string", "   Get management controller ID string"          },
84 	{ 0x06, "set_mc_id_string", "   Set management controller ID string"          },
85 	{ 0x07, "thermalpolicy", "      Thermal policy get/set"                       },
86 	{ 0x08, "get_temp_reading", "   Get Temperature Readings"                     },
87 	{ 0x09, "get_conf_param", "     Get DCMI Config Parameters"                   },
88 	{ 0x0A, "set_conf_param", "     Set DCMI Config Parameters"                   },
89 	{ 0x0B, "oob_discover", "       Ping/Pong Message for DCMI Discovery"         },
90 	{ 0xFF, NULL, NULL                                                        }
91 };
92 
93 /* get capabilites */
94 const struct dcmi_cmd dcmi_capable_vals[] = {
95 	{ 0x01, "platform", "            Lists the system capabilities" },
96 	{ 0x02, "mandatory_attributes", "Lists SEL, identification and"
97 		"temperature attributes"                                    },
98 	{ 0x03, "optional_attributes", " Lists power capabilities"      },
99 	{ 0x04, "managebility access", " Lists OOB channel information" },
100 	{ 0xFF, NULL, NULL                                              }
101 };
102 
103 /* platform capabilities
104  * Since they are actually in two bytes, we need three structs to make this
105  * human readable...
106  */
107 const struct dcmi_cmd dcmi_mandatory_platform_capabilities[] = {
108 	{ 0x01, "Identification support available", "" },
109 	{ 0x02, "SEL logging available", ""            },
110 	{ 0x03, "Chassis power available", ""          },
111 	{ 0x04, "Temperature monitor available", ""  },
112 	{ 0xFF, NULL, NULL                   }
113 };
114 
115 /* optional capabilities */
116 const struct dcmi_cmd dcmi_optional_platform_capabilities[] = {
117 	{ 0x01, "Power management available", ""       },
118 	{ 0xFF, NULL, NULL                   }
119 };
120 
121 /* access capabilties */
122 const struct dcmi_cmd dcmi_management_access_capabilities[] = {
123 	{ 0x01, "In-band KCS channel available", ""               },
124 	{ 0x02, "Out-of-band serial TMODE available", ""          },
125 	{ 0x03, "Out-of-band secondary LAN channel available", "" },
126 	{ 0x04, "Out-of-band primary LAN channel available", ""   },
127 	{ 0x05, "SOL enabled", ""                       },
128 	{ 0x06, "VLAN capable", ""      },
129 	{ 0xFF, NULL, NULL                              }
130 };
131 
132 /* identification capabilities */
133 const struct dcmi_cmd dcmi_id_capabilities_vals[] = {
134 	{ 0x01, "GUID", ""          },
135 	{ 0x02, "DHCP hostname", "" },
136 	{ 0x03, "Asset tag", ""    },
137 	{ 0xFF, NULL, NULL          }
138 };
139 
140 /* Configuration parameters*/
141 const struct dcmi_cmd dcmi_conf_param_vals[] = {
142 	{ 0x01, "activate_dhcp",   "\tActivate DHCP"},
143 	{ 0x02, "dhcp_config",     "\tDHCP Configuration" },
144 	{ 0x03, "init",            "\t\tInitial timeout interval"  },
145 	{ 0x04, "timeout",         "\t\tServer contact timeout interval"  },
146 	{ 0x05, "retry",           "\t\tServer contact retry interval"  },
147 	{ 0xFF, NULL, NULL          }
148 };
149 
150 
151 /* temperature monitoring capabilities */
152 const struct dcmi_cmd dcmi_temp_monitoring_vals[] = {
153 	{ 0x01, "inlet", "    Inlet air temperature sensors"  },
154 	{ 0x02, "cpu", "      CPU temperature sensors"        },
155 	{ 0x03, "baseboard", "Baseboard temperature sensors"  },
156 	{ 0xff, NULL, NULL                                    }
157 };
158 
159 /* These are not comands.  These are the DCMI temp sensors and their numbers
160  * If new sensors are added, they need to be added to this list with their
161  * sensor number
162  */
163 const struct dcmi_cmd dcmi_discvry_snsr_vals[] = {
164 	{ 0x40, "Inlet", "    Inlet air temperature sensors"  },
165 	{ 0x41, "CPU", "      CPU temperature sensors"        },
166 	{ 0x42, "Baseboard", "Baseboard temperature sensors"  },
167 	{ 0xff, NULL, NULL                                    }
168 };
169 
170 /* Temperature Readings */
171 const struct dcmi_cmd dcmi_temp_read_vals[] = {
172 	{ 0x40, "Inlet",        "Inlet air temperature(40h)         " },
173 	{ 0x41, "CPU",          "CPU temperature sensors(41h)       " },
174 	{ 0x42, "Baseboard",    "Baseboard temperature sensors(42h) " },
175 	{ 0xff, NULL, NULL                                    }
176 };
177 
178 /* power management/control commands */
179 const struct dcmi_cmd dcmi_pwrmgmt_vals[] = {
180 	{ 0x00, "reading", "   Get power related readings from the system" },
181 	{ 0x01, "get_limit", " Get the configured power limits"            },
182 	{ 0x02, "set_limit", " Set a power limit option"                   },
183 	{ 0x03, "activate", "  Activate the set power limit"               },
184 	{ 0x04, "deactivate", "Deactivate the set power limit"             },
185 	{ 0xFF, NULL, NULL                                                 }
186 };
187 
188 /* set power limit commands */
189 const struct dcmi_cmd dcmi_pwrmgmt_set_usage_vals[] = {
190 	{ 0x00, "action", "    <no_action | sel_logging | power_off>" },
191 	{ 0x01, "limit", "     <number in Watts>" },
192 	{ 0x02, "correction", "<number in milliseconds>" },
193 	{ 0x03, "sample", "    <number in seconds>" },
194 	{ 0xFF, NULL, NULL }
195 };
196 
197 /* power management/get action commands */
198 const struct dcmi_cmd dcmi_pwrmgmt_get_action_vals[] = {
199 	{ 0x00, "No Action", ""},
200 	{ 0x01, "Hard Power Off & Log Event to SEL", ""},
201 
202 	{ 0x02, "OEM reserved (02h)", ""},
203 	{ 0x03, "OEM reserved (03h)", ""},
204 	{ 0x04, "OEM reserved (04h)", ""},
205 	{ 0x05, "OEM reserved (05h)", ""},
206 	{ 0x06, "OEM reserved (06h)", ""},
207 	{ 0x07, "OEM reserved (07h)", ""},
208 	{ 0x08, "OEM reserved (08h)", ""},
209 	{ 0x09, "OEM reserved (09h)", ""},
210 	{ 0x0a, "OEM reserved (0ah)", ""},
211 	{ 0x0b, "OEM reserved (0bh)", ""},
212 	{ 0x0c, "OEM reserved (0ch)", ""},
213 	{ 0x0d, "OEM reserved (0dh)", ""},
214 	{ 0x0e, "OEM reserved (0eh)", ""},
215 	{ 0x0f, "OEM reserved (0fh)", ""},
216 	{ 0x10, "OEM reserved (10h)", ""},
217 
218 	{ 0x11, "Log Event to SEL", ""},
219 	{ 0xFF, NULL, NULL      }
220 };
221 
222 /* power management/set action commands */
223 const struct dcmi_cmd dcmi_pwrmgmt_action_vals[] = {
224 	{ 0x00, "no_action",   "No Action"},
225 	{ 0x01, "power_off",   "Hard Power Off & Log Event to SEL"},
226 	{ 0x11, "sel_logging", "Log Event to SEL"},
227 
228 	{ 0x02, "oem_02", "OEM reserved (02h)"},
229 	{ 0x03, "oem_03", "OEM reserved (03h)"},
230 	{ 0x04, "oem_04", "OEM reserved (04h)"},
231 	{ 0x05, "oem_05", "OEM reserved (05h)"},
232 	{ 0x06, "oem_06", "OEM reserved (06h)"},
233 	{ 0x07, "oem_07", "OEM reserved (07h)"},
234 	{ 0x08, "oem_08", "OEM reserved (08h)"},
235 	{ 0x09, "oem_09", "OEM reserved (09h)"},
236 	{ 0x0a, "oem_0a", "OEM reserved (0ah)"},
237 	{ 0x0b, "oem_0b", "OEM reserved (0bh)"},
238 	{ 0x0c, "oem_0c", "OEM reserved (0ch)"},
239 	{ 0x0d, "oem_0d", "OEM reserved (0dh)"},
240 	{ 0x0e, "oem_0e", "OEM reserved (0eh)"},
241 	{ 0x0f, "oem_0f", "OEM reserved (0fh)"},
242 	{ 0x10, "oem_10", "OEM reserved (10h)"},
243 
244 	{ 0xFF, NULL, NULL      }
245 };
246 
247 /* thermal policy action commands */
248 const struct dcmi_cmd dcmi_thermalpolicy_vals[] = {
249 	{ 0x00, "get", "Get thermal policy"  },
250 	{ 0x01, "set", "Set thermal policy"  },
251 	{ 0xFF, NULL, NULL      }
252 };
253 
254 /* thermal policy action commands */
255 const struct dcmi_cmd dcmi_confparameters_vals[] = {
256 	{ 0x00, "get", "Get configuration parameters"  },
257 	{ 0x01, "set", "Set configuration parameters"  },
258 	{ 0xFF, NULL, NULL      }
259 };
260 
261 /* entityIDs used in thermap policy */
262 const struct dcmi_cmd dcmi_thermalpolicy_set_parameters_vals[] = {
263 	{ 0x00, "volatile", "   Current Power Cycle"        },
264 	{ 0x01, "nonvolatile", "Set across power cycles"        },
265 	{ 0x01, "poweroff", "   Hard Power Off system"          },
266 	{ 0x00, "nopoweroff", " No 'Hard Power Off' action"         },
267 	{ 0x01, "sel", "        Log event to SEL"   },
268 	{ 0x00, "nosel", "      No 'Log event to SEL' action"   },
269 	{ 0x00, "disabled", "   Disabled"   },
270 	{ 0x00, NULL,    NULL                   }
271 };
272 
273 
274 /* DCMI command specific completion code results per 1.0 spec
275  * 80h - parameter not supported.
276  * 81h - attempt to set the ‘set in progress’ value (in parameter #0) when not
277  *       in the ‘set complete’ state. (This completion code provides a way to
278  *       recognize that another party has already ‘claimed’ the parameters)
279  * 82h - attempt to write read-only parameter
280  * 82h - set not supported on selected channel (e.g. channel is session-less.)
281  * 83h - access mode not supported
282  * 84h – Power Limit out of range
283  * 85h – Correction Time out of range
284  * 89h – Statistics Reporting Period out of range
285  */
286 const struct valstr dcmi_ccode_vals[] = {
287 	{ 0x80, "Parameter not supported" },
288 	{ 0x81, "Something else has already claimed these parameters" },
289 	{ 0x82, "Not supported or failed to write a read-only parameter" },
290 	{ 0x83, "Access mode is not supported" },
291 	{ 0x84, "Power/Thermal limit out of range" },
292 	{ 0x85, "Correction/Exception time out of range" },
293 	{ 0x89, "Sample/Statistics Reporting period out of range" },
294 	{ 0x8A, "Power limit already active" },
295 	{ 0xFF, NULL }
296 };
297 
298 /* End strings */
299 
300 /* This was taken from print_valstr() from helper.c.  It serves the same
301  * purpose but with out the extra formatting.  This function simply prints
302  * the dcmi_cmd struct provided.  verthorz specifies to print vertically or
303  * horizontally.  If the string is printed horizontally then a | will be
304  * printed between each instance of vs[i].str until it is NULL
305  *
306  * @vs:         value string list to print
307  * @title:      name of this value string list
308  * @loglevel:   what log level to print, -1 for stdout
309  * @verthorz:   printed vertically or horizontally, 0 or 1
310  */
311 void
312 print_strs(const struct dcmi_cmd * vs, const char * title, int loglevel,
313 		int verthorz)
314 {
315 	int i;
316 
317 	if (vs == NULL)
318 		return;
319 
320 	if (title != NULL) {
321 		if (loglevel < 0)
322 			printf("\n%s\n", title);
323 		else
324 			lprintf(loglevel, "\n%s", title);
325 	}
326 	for (i = 0; vs[i].str != NULL; i++) {
327 		if (loglevel < 0) {
328 			if (vs[i].val < 256)
329 				if (verthorz == 0)
330 					printf("    %s    %s\n", vs[i].str, vs[i].desc);
331 				else
332 					printf("%s", vs[i].str);
333 			else if (verthorz == 0)
334 				printf("    %s    %s\n", vs[i].str, vs[i].desc);
335 			else
336 				printf("%s", vs[i].str);
337 		} else {
338 			if (vs[i].val < 256)
339 				lprintf(loglevel, "    %s    %s", vs[i].str, vs[i].desc);
340 			else
341 				lprintf(loglevel, "    %s    %s", vs[i].str, vs[i].desc);
342 		}
343 		/* Check to see if this is NOT the last element in vs.str if true
344 		 * print the | else don't print anything.
345 		 */
346 		if ((verthorz == 1) && (vs[i+1].str != NULL))
347 			printf(" | ");
348 	}
349 	if (verthorz == 0) {
350 		if (loglevel < 0) {
351 			printf("\n");
352 		} else {
353 			lprintf(loglevel, "");
354 		}
355 	}
356 }
357 
358 /* This was taken from str2val() from helper.c.  It serves the same
359  * purpose but with the addition of a desc field from the structure.
360  * This function converts the str from the dcmi_cmd struct provided to the
361  * value associated to the compared string in the struct.
362  *
363  * @str:        string to compare against
364  * @vs:         dcmi_cmd structure
365  */
366 uint16_t
367 str2val2(const char *str, const struct dcmi_cmd *vs)
368 {
369 	int i;
370 	if (vs == NULL || str == NULL) {
371 		return 0;
372 	}
373 	for (i = 0; vs[i].str != NULL; i++) {
374 		if (strncasecmp(vs[i].str, str,
375 					__maxlen(str, vs[i].str)) == 0) {
376 			return vs[i].val;
377 		}
378 	}
379 	return vs[i].val;
380 }
381 
382 /* This was taken from val2str() from helper.c.  It serves the same
383  * purpose but with the addition of a desc field from the structure.
384  * This function converts the val and returns a string from the dcmi_cmd
385  * struct provided in the struct.
386  *
387  * @val:        value to compare against
388  * @vs:         dcmi_cmd structure
389  */
390 const char *
391 val2str2(uint16_t val, const struct dcmi_cmd *vs)
392 {
393 	static char un_str[32];
394 	int i;
395 
396 	if (vs == NULL)
397 		return NULL;
398 
399 	for (i = 0; vs[i].str != NULL; i++) {
400 		if (vs[i].val == val)
401 			return vs[i].str;
402 	}
403 	memset(un_str, 0, 32);
404 	snprintf(un_str, 32, "Unknown (0x%x)", val);
405 	return un_str;
406 }
407 
408 /* check the DCMI response   from the BMC
409  * @rsp:       Response data structure
410  */
411 static int
412 chk_rsp(struct ipmi_rs * rsp)
413 {
414 	/* if the response from the intf is NULL then the BMC is experiencing
415 	 * some issue and cannot complete the command
416 	 */
417 	if (rsp == NULL) {
418 		lprintf(LOG_ERR, "\n    Unable to get DCMI information");
419 		return 1;
420 	}
421 	/* if the completion code is greater than zero there was an error.  We'll
422 	 * use val2str from helper.c to print the error from either the DCMI
423 	 * completion code struct or the generic IPMI completion_code_vals struct
424 	 */
425 	if ((rsp->ccode >= 0x80) && (rsp->ccode <= 0x8F)) {
426 		lprintf(LOG_ERR, "\n    DCMI request failed because: %s (%x)",
427 				val2str(rsp->ccode, dcmi_ccode_vals), rsp->ccode);
428 		return 1;
429 	} else if (rsp->ccode > 0) {
430 		lprintf(LOG_ERR, "\n    DCMI request failed because: %s (%x)",
431 				val2str(rsp->ccode, completion_code_vals), rsp->ccode);
432 		return 1;
433 	}
434 	/* check to make sure this is a DCMI firmware */
435 	if(rsp->data[0] != IPMI_DCMI) {
436 		printf("\n    A valid DCMI command was not returned! (%x)", rsp->data[0]);
437 		return 1;
438 	}
439 	return 0;
440 }
441 
442 /* Get capabilities ipmi response
443  *
444  * This function returns the available capabilities of the platform.
445  * The reason it returns in the rsp struct is so that it can be used for other
446  * purposes.
447  *
448  * returns ipmi response structure
449  *
450  * @intf:   ipmi interface handler
451  * @selector: Parameter selector
452  */
453 struct ipmi_rs *
454 ipmi_dcmi_getcapabilities(struct ipmi_intf * intf, uint8_t selector)
455 {
456 	struct ipmi_rq req; /* request data to send to the BMC */
457 	uint8_t msg_data[2]; /* 'raw' data to be sent to the BMC */
458 
459 	msg_data[0] = IPMI_DCMI; /* Group Extension Identification */
460 	msg_data[1] = selector;
461 
462 	memset(&req, 0, sizeof(req));
463 	req.msg.netfn = IPMI_NETFN_DCGRP; /* 0x2C per 1.0 spec */
464 	req.msg.cmd = IPMI_DCMI_COMPAT; /* 0x01 per 1.0 spec */
465 	req.msg.data = msg_data; /* 0xDC 0x01 or the msg_data above */
466 	req.msg.data_len = 2; /* How many times does req.msg.data need to read */
467 
468 	return intf->sendrecv(intf, &req);
469 }
470 /* end capabilities struct */
471 
472 /* Displays capabilities from structure
473  * returns void
474  *
475  * @cmd:        dcmi_cmd structure
476  * @data_val:  holds value of what to display
477  */
478 void
479 display_capabilities_attributes(const struct dcmi_cmd *cmd, uint8_t data_val)
480 {
481 	uint8_t i;
482 	for (i = 0x01; cmd[i-1].val != 0xFF; i++) {
483 		if (data_val & (1<<(i-1))) {
484 			printf("        %s\n", val2str2(i, cmd));
485 		}
486 	}
487 }
488 
489 static int
490 ipmi_dcmi_prnt_oobDiscover(struct ipmi_intf * intf)
491 {
492 # ifndef IPMI_INTF_LANPLUS
493 	lprintf(LOG_ERR,
494 			"DCMI Discovery is available only when LANplus(IPMI v2.0) is enabled.");
495 	return (-1);
496 # else
497 	int rc;
498 	struct ipmi_session *s;
499 
500 	if (intf->opened == 0 && intf->open != NULL) {
501 		if (intf->open(intf) < 0)
502 			return (-1);
503 	}
504 	if (intf == NULL || intf->session == NULL)
505 		return -1;
506 
507 	s = intf->session;
508 
509 	if (s->port == 0)
510 		s->port = IPMI_LAN_PORT;
511 	if (s->privlvl == 0)
512 		s->privlvl = IPMI_SESSION_PRIV_ADMIN;
513 	if (s->timeout == 0)
514 		s->timeout = IPMI_LAN_TIMEOUT;
515 	if (s->retry == 0)
516 		s->retry = IPMI_LAN_RETRY;
517 
518 	if (s->hostname == NULL || strlen((const char *)s->hostname) == 0) {
519 		lprintf(LOG_ERR, "No hostname specified!");
520 		return -1;
521 	}
522 
523 	intf->abort = 1;
524 	intf->session->sol_data.sequence_number = 1;
525 
526 	if (ipmi_intf_socket_connect (intf)  == -1) {
527 		lprintf(LOG_ERR, "Could not open socket!");
528 		return -1;
529 	}
530 
531 	if (intf->fd < 0) {
532 		lperror(LOG_ERR, "Connect to %s failed",
533 			s->hostname);
534 		intf->close(intf);
535 		return -1;
536 	}
537 
538 	intf->opened = 1;
539 
540 	/* Lets ping/pong */
541 	return ipmiv2_lan_ping(intf);
542 # endif
543 }
544 
545 /* This is the get DCMI Capabilities function to see what the BMC supports.
546  *
547  * returns 0 with out error -1 with any errors
548  *
549  * @intf:      ipmi interface handler
550  * @selector:  selection parameter
551  */
552 static int
553 ipmi_dcmi_prnt_getcapabilities(struct ipmi_intf * intf, uint8_t selector)
554 {
555 	uint8_t i;
556 	uint8_t bit_shifter = 0;
557 	struct capabilities cape;
558 	struct ipmi_rs * rsp;
559 	rsp = ipmi_dcmi_getcapabilities(intf, selector);
560 
561 	if(chk_rsp(rsp))
562 		return -1;
563 
564 	/* if there were no errors, the command worked! */
565 	memcpy(&cape, rsp->data, sizeof (cape));
566 	/* check to make sure that this is a 1.0/1.1/1.5 command */
567 	if ((cape.conformance != IPMI_DCMI_CONFORM)
568 			&& (cape.conformance != IPMI_DCMI_1_1_CONFORM)
569 			&& (cape.conformance != IPMI_DCMI_1_5_CONFORM)) {
570 		lprintf(LOG_ERR,
571 				"ERROR!  This command is not available on this platform");
572 		return -1;
573 	}
574 	/* check to make sure that this is a rev .01 or .02 */
575 	if (cape.revision != 0x01 && cape.revision != 0x02) {
576 		lprintf(LOG_ERR,
577 				"ERROR!  This command is not compatible with this version");
578 		return -1;
579 	}
580 	/* 0x01 - platform capabilities
581 	 * 0x02 - Manageability Access Capabilities
582 	 * 0x03 - SEL Capability
583 	 * 0x04 - Identification Capability
584 	 * 0x05 - LAN Out-Of-Band Capability
585 	 * 0x06 - Serial Out-Of-Band TMODE Capability
586 	 */
587 	switch (selector) {
588 	case 0x01:
589 		printf("    Supported DCMI capabilities:\n");
590 		/* loop through each of the entries in the first byte from the
591 		 * struct
592 		 */
593 		printf("\n         Mandatory platform capabilties\n");
594 		display_capabilities_attributes(
595 				dcmi_mandatory_platform_capabilities, cape.data_byte1);
596 		/* loop through each of the entries in the second byte from the
597 		 * struct
598 		 */
599 		printf("\n         Optional platform capabilties\n");
600 		display_capabilities_attributes(
601 				dcmi_optional_platform_capabilities, cape.data_byte2);
602 		/* loop through each of the entries in the third byte from the
603 		 * struct
604 		 */
605 		printf("\n         Managebility access capabilties\n");
606 		display_capabilities_attributes(
607 				dcmi_management_access_capabilities, cape.data_byte3);
608 		break;
609 	case 0x02:
610 		printf("\n    Mandatory platform attributes:\n");
611 		/* byte 1 & 2 data */
612 		printf("\n         SEL Attributes: ");
613 		printf("\n               SEL automatic rollover is ");
614 		/* mask the 2nd byte of the data response with 10000000b or 0x80
615 		 * because of the endian-ness the 15th bit is in the second byte
616 		 */
617 		if ((cape.data_byte2 & 0x80))
618 			printf("enabled");
619 		else
620 			printf("not present");
621 		/* since the number of SEL entries is split across the two data
622 		 * bytes we will need to bit shift and append them together again
623 		 */
624 		/* cast cape.data_byte1 as 16 bits */
625 		uint16_t sel_entries = (uint16_t)cape.data_byte1;
626 		/* or sel_entries with byte 2 and shift it 8 places  */
627 		sel_entries |= (uint16_t)cape.data_byte2 << 8;
628 		printf("\n               %d SEL entries\n", sel_entries & 0xFFF);
629 		/* byte 3 data */
630 		printf("\n         Identification Attributes: \n");
631 		display_capabilities_attributes(
632 				dcmi_id_capabilities_vals, cape.data_byte3);
633 		/* byte 4 data */
634 		printf("\n         Temperature Monitoring Attributes: \n");
635 		display_capabilities_attributes(dcmi_temp_monitoring_vals,
636 				cape.data_byte4);
637 		break;
638 	case 0x03:
639 		printf("\n    Optional Platform Attributes: \n");
640 		/* Power Management */
641 		printf("\n         Power Management:\n");
642 		if (cape.data_byte1 == 0x40) {
643 			printf("                Slave address of device: 20h (BMC)\n" );
644 		} else {
645 			printf("                Slave address of device: %xh (8bits)"
646 					"(Satellite/External controller)\n",
647 					cape.data_byte1);
648 		}
649 		/* Controller channel number (4-7) bits */
650 		if ((cape.data_byte2>>4) == 0x00) {
651 			printf("                Channel number is 0h (Primary BMC)\n");
652 		} else {
653 			printf("                Channel number is %xh \n",
654 					(cape.data_byte2>>4));
655 		}
656 		/* Device revision (0-3) */
657 		printf("                    Device revision is %d \n",
658 				cape.data_byte2 &0xf);
659 		break;
660 	case 0x04:
661 		/* LAN */
662 		printf("\n    Manageability Access Attributes: \n");
663 		if (cape.data_byte1 == 0xFF) {
664 			printf("         Primary LAN channel is not available for OOB\n");
665 		} else {
666 			printf("         Primary LAN channel number: %d is available\n",
667 					cape.data_byte1);
668 		}
669 		if (cape.data_byte2 == 0xFF) {
670 			printf("         Secondary LAN channel is not available for OOB\n");
671 		} else {
672 			printf("         Secondary LAN channel number: %d is available\n",
673 					cape.data_byte2);
674 		}
675 		/* serial */
676 		if (cape.data_byte3 == 0xFF) {
677 			printf("         No serial channel is available\n");
678 		} else {
679 			printf("         Serial channel number: %d is available\n",
680 					cape.data_byte3);
681 		}
682 		break;
683 	default:
684 		return -1;
685 	}
686 	return 0;
687 	/* return intf->sendrecv(intf, &req); */
688 }
689 
690 /* This is the get asset tag command.  This checks the length of the asset tag
691  * with the first read, then reads n number of bytes thereafter to get the
692  * complete asset tag.
693  *
694  * @intf:   ipmi interface handler
695  * @offset: where to start reading the asset tag
696  * @length: how much to read
697  *
698  * returns ipmi_rs structure
699  */
700 struct ipmi_rs *
701 ipmi_dcmi_getassettag(struct ipmi_intf * intf, uint8_t offset, uint8_t length)
702 {
703 	struct ipmi_rq req; /* request data to send to the BMC */
704 	uint8_t msg_data[3]; /* 'raw' data to be sent to the BMC */
705 
706 	msg_data[0] = IPMI_DCMI; /* Group Extension Identification */
707 	msg_data[1] = offset; /* offset 0 */
708 	msg_data[2] = length; /* read one byte */
709 
710 	memset(&req, 0, sizeof(req));
711 	req.msg.netfn = IPMI_NETFN_DCGRP; /* 0x2C per 1.1 spec */
712 	req.msg.cmd = IPMI_DCMI_GETASSET; /* 0x01 per 1.1 spec */
713 	req.msg.data = msg_data; /* msg_data above */
714 	req.msg.data_len = 3; /* How many times does req.msg.data need to read */
715 	return intf->sendrecv(intf, &req);
716 }
717 
718 /* This is the get asset tag command.  The function first checks to see if the
719  * platform is capable of getting the asset tag by calling the getcapabilities
720  * function and checking the response.  Then it checks the length of the asset
721  * tag with the first read, then x number of reads thereafter to get the asset
722  * complete asset tag then print it.
723  *
724  * @intf:   ipmi interface handler
725  *
726  * returns 0 if no failure, -1 with a failure
727  */
728 static int
729 ipmi_dcmi_prnt_getassettag(struct ipmi_intf * intf)
730 {
731 	uint8_t data_byte2;
732 	struct ipmi_rs * rsp; /* ipmi response */
733 	uint8_t taglength = 0;
734 	uint8_t getlength = 0;
735 	uint8_t offset = 0;
736 	uint8_t i;
737 	/* now let's get the asset tag length */
738 	rsp = ipmi_dcmi_getassettag(intf, 0, 0);
739 	if (chk_rsp(rsp)) {
740 		return -1;
741 	}
742 	taglength = rsp->data[1];
743 	printf("\n Asset tag: ");
744 	while (taglength) {
745 		getlength = taglength / DCMI_MAX_BYTE_SIZE ?
746 			DCMI_MAX_BYTE_SIZE : taglength%DCMI_MAX_BYTE_SIZE;
747 		rsp = ipmi_dcmi_getassettag(intf, offset, getlength);
748 		/* macro has no effect here where can generate sig segv
749 		 * if rsp occurs with null
750 		 */
751 		if (rsp != NULL) {
752 			GOOD_ASSET_TAG_CCODE(rsp->ccode);
753 		}
754 		if (chk_rsp(rsp)) {
755 			return -1;
756 		}
757 		for (i=0; i<getlength; i++) {
758 			printf("%c", rsp->data[i+2]);
759 		}
760 		offset += getlength;
761 		taglength -= getlength;
762 	}
763 	printf("\n");
764 	return 0;
765 }
766 
767 /* This is the set asset tag command.  This checks the length of the asset tag
768  * with the first read, then reads n number of bytes thereafter to set the
769  * complete asset tag.
770  *
771  * @intf:   ipmi interface handler
772  * @offset: offset to write
773  * @length: number of bytes to write (16 bytes maximum)
774  * @data:   data to write
775  *
776  * returns ipmi_rs structure
777  */
778 struct ipmi_rs *
779 ipmi_dcmi_setassettag(struct ipmi_intf * intf, uint8_t offset, uint8_t length,
780 		uint8_t *data)
781 {
782 	struct ipmi_rq req; /* request data to send to the BMC */
783 	uint8_t msg_data[3+length]; /* 'raw' data to be sent to the BMC */
784 
785 	msg_data[0] = IPMI_DCMI; /* Group Extension Identification */
786 	msg_data[1] = offset; /* offset 0 */
787 	msg_data[2] = length; /* read one byte */
788 
789 	memset(&req, 0, sizeof(req));
790 	req.msg.netfn = IPMI_NETFN_DCGRP; /* 0x2C per 1.1 spec */
791 	req.msg.cmd = IPMI_DCMI_SETASSET; /* 0x08 per 1.1 spec */
792 	req.msg.data = msg_data; /* msg_data above */
793 	/* How many times does req.msg.data need to read */
794 	req.msg.data_len = length + 3;
795 	memcpy(req.msg.data + 3, data, length);
796 
797 	return intf->sendrecv(intf, &req);
798 }
799 
800 static int
801 ipmi_dcmi_prnt_setassettag(struct ipmi_intf * intf, uint8_t * data)
802 {
803 	uint8_t data_byte2;
804 	struct ipmi_rs * rsp; /* ipmi response */
805 	uint8_t tmpData[DCMI_MAX_BYTE_SIZE];
806 	uint8_t taglength = 0;
807 	uint8_t getlength = 0;
808 	uint8_t offset = 0;
809 	uint8_t i;
810 
811 	/* now let's get the asset tag length */
812 	taglength = strlen(data);
813 	if (taglength > 64){
814 		lprintf(LOG_ERR, "\nValue is too long.");
815 		return -1;
816 	}
817 	printf("\n Set Asset Tag: ");
818 	while (taglength) {
819 		getlength = taglength / DCMI_MAX_BYTE_SIZE ?
820 			DCMI_MAX_BYTE_SIZE : taglength%DCMI_MAX_BYTE_SIZE;
821 		memcpy(tmpData, data + offset, getlength);
822 		rsp = ipmi_dcmi_setassettag(intf, offset, getlength, tmpData);
823 		if (chk_rsp(rsp)) {
824 			return -1;
825 		}
826 		for (i=0; i<getlength; i++) {
827 			printf("%c", tmpData[i]);
828 		}
829 		offset += getlength;
830 		taglength -= getlength;
831 	}
832 	printf("\n");
833 	return 0;
834 }
835 
836 /* Management Controller Identifier String is provided in order to accommodate
837  * the requirement for the management controllers to identify themselves.
838  *
839  * @intf:   ipmi interface handler
840  * @offset: offset to read
841  * @length: number of bytes to read (16 bytes maximum)
842  *
843  * returns ipmi_rs structure
844  */
845 struct ipmi_rs *
846 ipmi_dcmi_getmngctrlids(struct ipmi_intf * intf, uint8_t offset, uint8_t length)
847 {
848 	struct ipmi_rq req; /* request data to send to the BMC */
849 	uint8_t msg_data[3]; /* 'raw' data to be sent to the BMC */
850 
851 	msg_data[0] = IPMI_DCMI; /* Group Extension Identification */
852 	msg_data[1] = offset; /* offset 0 */
853 	msg_data[2] = length; /* read one byte */
854 
855 	memset(&req, 0, sizeof(req));
856 	req.msg.netfn = IPMI_NETFN_DCGRP; /* 0x2C per 1.1 spec */
857 	req.msg.cmd = IPMI_DCMI_GETMNGCTRLIDS; /* 0x09 per 1.1 spec */
858 	req.msg.data = msg_data; /* msg_data above */
859 	/* How many times does req.msg.data need to read */
860 	req.msg.data_len = 3;
861 	return intf->sendrecv(intf, &req);
862 }
863 
864 static int
865 ipmi_dcmi_prnt_getmngctrlids(struct ipmi_intf * intf)
866 {
867 	uint8_t data_byte2;
868 	struct ipmi_rs * rsp; /* ipmi response */
869 	uint8_t taglength = 0;
870 	uint8_t getlength = 0;
871 	uint8_t offset = 0;
872 	uint8_t i;
873 
874 	/* now let's get the asset tag length */
875 	rsp = ipmi_dcmi_getmngctrlids(intf, 0, 1);
876 
877 	if (chk_rsp(rsp)) {
878 		return -1;
879 	}
880 
881 	taglength = rsp->data[1];
882 
883 	printf("\n Get Management Controller Identifier String: ");
884 	while (taglength) {
885 		getlength = taglength / DCMI_MAX_BYTE_SIZE ?
886 			DCMI_MAX_BYTE_SIZE : taglength%DCMI_MAX_BYTE_SIZE;
887 		rsp = ipmi_dcmi_getmngctrlids(intf, offset, getlength);
888 
889 		if (chk_rsp(rsp)) {
890 			return -1;
891 		}
892 		for (i=0; i<getlength; i++) {
893 			printf("%c", rsp->data[i+2]);
894 		}
895 		offset += getlength;
896 		taglength -= getlength;
897 	}
898 	printf("\n");
899 	return 0;
900 }
901 
902 /* Management Controller Identifier String is provided in order to accommodate
903  * the requirement for the management controllers to identify themselves.
904  *
905  * @intf:   ipmi interface handler
906  * @offset: offset to write
907  * @length: number of bytes to write (16 bytes maximum)
908  * @data:   data to write
909  *
910  * returns ipmi_rs structure
911  */
912 struct ipmi_rs *
913 ipmi_dcmi_setmngctrlids(struct ipmi_intf * intf, uint8_t offset, uint8_t length,
914 		uint8_t *data)
915 {
916 	struct ipmi_rq req; /* request data to send to the BMC */
917 	uint8_t msg_data[3+length]; /* 'raw' data to be sent to the BMC */
918 
919 	msg_data[0] = IPMI_DCMI; /* Group Extension Identification */
920 	msg_data[1] = offset; /* offset 0 */
921 	msg_data[2] = length; /* read one byte */
922 
923 	memset(&req, 0, sizeof(req));
924 	req.msg.netfn = IPMI_NETFN_DCGRP; /* 0x2C per 1.1 spec */
925 	req.msg.cmd = IPMI_DCMI_SETMNGCTRLIDS; /* 0x0A per 1.1 spec */
926 	req.msg.data = msg_data; /* msg_data above */
927 	/* How many times does req.msg.data need to read */
928 	req.msg.data_len = 3 + length;
929 	memcpy(req.msg.data + 3, data, length);
930 
931 	return intf->sendrecv(intf, &req);
932 }
933 
934 /* Set Asset Tag command provides ability for the management console to set the
935  * asset tag as appropriate. Management controller is not responsible for the
936  * data format used for the Asset Tag once modified by IPDC.
937  *
938  * @intf:   ipmi interface handler
939  *
940  * returns 0 if no failure, -1 with a failure
941  */
942 static int
943 ipmi_dcmi_prnt_setmngctrlids(struct ipmi_intf * intf, uint8_t * data)
944 {
945 	uint8_t data_byte2;
946 	struct ipmi_rs * rsp; /* ipmi response */
947 	uint8_t tmpData[DCMI_MAX_BYTE_SIZE];
948 	uint8_t taglength = 0;
949 	uint8_t getlength = 0;
950 	uint8_t offset = 0;
951 	uint8_t i;
952 
953 	data += '\0';
954 	taglength = strlen(data) +1;
955 
956 	if (taglength > 64) {
957 		lprintf(LOG_ERR, "\nValue is too long.");
958 		return -1;
959 	}
960 
961 	printf("\n Set Management Controller Identifier String Command: ");
962 	while (taglength) {
963 		getlength = taglength / DCMI_MAX_BYTE_SIZE ?
964 			DCMI_MAX_BYTE_SIZE : taglength%DCMI_MAX_BYTE_SIZE;
965 		memcpy(tmpData, data + offset, getlength);
966 		rsp = ipmi_dcmi_setmngctrlids(intf, offset, getlength, tmpData);
967 		/* because after call "Set mc id string" RMCP+ will go down
968 		 * we have no "rsp"
969 		 */
970 		if (strncmp(intf->name, "lanplus", 7)) {
971 			if (chk_rsp(rsp)) {
972 				return -1;
973 			}
974 		}
975 		for (i=0; i<getlength; i++) {
976 			printf("%c", tmpData[i]);
977 		}
978 		offset += getlength;
979 		taglength -= getlength;
980 	}
981 	printf("\n");
982 	return 0;
983 }
984 
985 /* Issues a discovery command to see what sensors are available on the target.
986  * system.
987  *
988  * @intf:   ipmi interface handler
989  * @isnsr:  entity ID
990  * @offset:   offset (Entity instace start)
991  *
992  * returns ipmi_rs structure
993  */
994 struct ipmi_rs *
995 ipmi_dcmi_discvry_snsr(struct ipmi_intf * intf, uint8_t isnsr, uint8_t offset)
996 {
997 	struct ipmi_rq req; /* ipmi request struct */
998 	uint8_t msg_data[5]; /* number of request data bytes */
999 
1000 	msg_data[0] = IPMI_DCMI; /* Group Extension Identification */
1001 	msg_data[1] = 0x01; /* Senser Type = Temp (01h) */
1002 	msg_data[2] = isnsr; /* Sensor Number */
1003 	msg_data[3] = 0x00; /* Entity Instance, set to read all instances */
1004 	msg_data[4] = offset; /* Entity instace start */
1005 
1006 	memset(&req, 0, sizeof(req));
1007 	req.msg.netfn = IPMI_NETFN_DCGRP;
1008 	req.msg.cmd = IPMI_DCMI_GETSNSR;
1009 	req.msg.data = msg_data; /* Contents above */
1010 	req.msg.data_len = 5; /* how many times does req.msg.data need to read */
1011 
1012 	return intf->sendrecv(intf, &req);
1013 }
1014 
1015 /* DCMI sensor discovery
1016  * Uses the dcmi_discvry_snsr_vals struct to print its string and
1017  * uses the numeric values to request the sensor sdr record id.
1018  *
1019  * @intf:   ipmi interface handler
1020  * @isnsr:  entity ID
1021  * @ient:   sensor entity id
1022  */
1023 static int
1024 ipmi_dcmi_prnt_discvry_snsr(struct ipmi_intf * intf, uint8_t isnsr)
1025 {
1026 	int i = 0;
1027 	struct ipmi_rs * rsp; /* ipmi response */
1028 	uint8_t records = 0;
1029 	int8_t instances = 0;
1030 	uint8_t offset = 0;
1031 	uint16_t record_id = 0;
1032 	uint8_t id_buff[16]; /* enough for 8 record IDs */
1033 	rsp = ipmi_dcmi_discvry_snsr(intf, isnsr, 0);
1034 	if (chk_rsp(rsp)) {
1035 		return -1;
1036 	}
1037 	instances = rsp->data[1];
1038 	printf("\n%s: %d temperature sensor%s found:\n",
1039 			val2str2(isnsr, dcmi_discvry_snsr_vals),
1040 			instances,
1041 			(instances > 1) ? "s" : "");
1042 	while(instances > 0) {
1043 		ipmi_dcmi_discvry_snsr(intf, isnsr, offset);
1044 		if (chk_rsp(rsp)) {
1045 			return -1;
1046 		}
1047 		records = rsp->data[2];
1048 		/* cache the data since it may be destroyed by subsequent
1049 		 * ipmi_xxx calls
1050 		 */
1051 		memcpy(id_buff, &rsp->data[3], 16);
1052 		for (i=0; i<records; i++) {
1053 			/* Record ID is in little endian format */
1054 			record_id = (id_buff[2*i + 1] << 8) + id_buff[2*i];
1055 			printf("Record ID 0x%04x: ", record_id);
1056 			ipmi_print_sensor_info(intf, record_id);
1057 		}
1058 		offset += 8;
1059 		instances -= records;
1060 	}
1061 	return 0;
1062 }
1063 /* end sensor discovery */
1064 
1065 /* Power Management get power reading
1066  *
1067  * @intf:   ipmi interface handler
1068  */
1069 static int
1070 ipmi_dcmi_pwr_rd(struct ipmi_intf * intf)
1071 {
1072 	struct ipmi_rs * rsp;
1073 	struct ipmi_rq req;
1074 	struct power_reading val;
1075 	struct tm tm_t;
1076 	time_t t;
1077 	uint8_t msg_data[4]; /* number of request data bytes */
1078 	memset(&tm_t, 0, sizeof(tm_t));
1079 	memset(&t, 0, sizeof(t));
1080 
1081 	msg_data[0] = IPMI_DCMI; /* Group Extension Identification */
1082 	msg_data[1] = 0x01; /* Mode Power Status */
1083 	msg_data[2] = 0x00; /* reserved */
1084 	msg_data[3] = 0x00; /* reserved */
1085 
1086 	memset(&req, 0, sizeof(req));
1087 	req.msg.netfn = IPMI_NETFN_DCGRP;
1088 	req.msg.cmd = IPMI_DCMI_GETRED; /* Get power reading */
1089 	req.msg.data = msg_data; /* msg_data above */
1090 	req.msg.data_len = 4; /* how many times does req.msg.data need to read */
1091 
1092 	rsp = intf->sendrecv(intf, &req);
1093 
1094 	if (chk_rsp(rsp)) {
1095 		return -1;
1096 	}
1097 	/* rsp->data[0] is equal to response data byte 2 in spec */
1098 	/* printf("Group Extension Identification: %02x\n", rsp->data[0]); */
1099 	memcpy(&val, rsp->data, sizeof (val));
1100 	t = val.time_stamp;
1101 	gmtime_r(&t, &tm_t);
1102 	printf("\n");
1103 	printf("    Instantaneous power reading:              %8d Watts\n",
1104 			val.curr_pwr);
1105 	printf("    Minimum during sampling period:           %8d Watts\n",
1106 			val.min_sample);
1107 	printf("    Maximum during sampling period:           %8d Watts\n",
1108 			val.max_sample);
1109 	printf("    Average power reading over sample period: %8d Watts\n",
1110 			val.avg_pwr);
1111 	printf("    IPMI timestamp:                           %s",
1112 			asctime(&tm_t));
1113 	printf("    Sampling period:                          %08d Milliseconds\n",
1114 			val.sample);
1115 	printf("    Power reading state is:                   ");
1116 	/* mask the rsp->data so that we only care about bit 6 */
1117 	if((val.state & 0x40) == 0x40) {
1118 		printf("activated");
1119 	} else {
1120 		printf("deactivated");
1121 	}
1122 	printf("\n\n");
1123 	return 0;
1124 }
1125 /* end Power Management get reading */
1126 
1127 
1128 /* This is the get thermalpolicy command.
1129  *
1130  * @intf:   ipmi interface handler
1131  */
1132 int
1133 ipmi_dcmi_getthermalpolicy(struct ipmi_intf * intf, uint8_t entityID,
1134 		uint8_t entityInstance)
1135 {
1136 	struct ipmi_rs * rsp;
1137 	struct ipmi_rq req;
1138 	struct thermal_limit val;
1139 	uint8_t msg_data[3]; /* number of request data bytes */
1140 
1141 	msg_data[0] = IPMI_DCMI; /* Group Extension Identification */
1142 	msg_data[1] = entityID; /* Inlet Temperature DCMI ID*/
1143 	msg_data[2] = entityInstance; /* Entity Instance */
1144 
1145 	memset(&req, 0, sizeof(req));
1146 	req.msg.netfn = IPMI_NETFN_DCGRP;
1147 	req.msg.cmd = IPMI_DCMI_GETTERMALLIMIT; /* Get thermal policy reading */
1148 	req.msg.data = msg_data; /* msg_data above */
1149 	req.msg.data_len = 3; /* how many times does req.msg.data need to read */
1150 
1151 	rsp = intf->sendrecv(intf, &req);
1152 
1153 	if (chk_rsp(rsp)) {
1154 		return -1;
1155 	}
1156 	/* rsp->data[0] is equal to response data byte 2 in spec */
1157 	memcpy(&val, rsp->data, sizeof (val));
1158 	printf("\n");
1159 	printf("    Persistance flag is:                      %s\n",
1160 			((val.exceptionActions & 0x80) ? "set" : "notset"));
1161 	printf("    Exception Actions, taken if the Temperature Limit exceeded:\n");
1162 	printf("        Hard Power Off system and log event:  %s\n",
1163 			((val.exceptionActions & 0x40) ? "active":"inactive"));
1164 	printf("        Log event to SEL only:                %s\n",
1165 			((val.exceptionActions & 0x20) ? "active":"inactive"));
1166 	printf("    Temperature Limit                         %d degrees\n",
1167 			val.tempLimit);
1168 	printf("    Exception Time                            %d seconds\n",
1169 			val.exceptionTime);
1170 	printf("\n\n");
1171 	return 0;
1172 }
1173 
1174 /* This is the set thermalpolicy command.
1175  *
1176  * @intf:   ipmi interface handler
1177  */
1178 int
1179 ipmi_dcmi_setthermalpolicy(struct ipmi_intf * intf,
1180 		uint8_t entityID,
1181 		uint8_t entityInst,
1182 		uint8_t persistanceFlag,
1183 		uint8_t actionHardPowerOff,
1184 		uint8_t actionLogToSEL,
1185 		uint8_t tempLimit,
1186 		uint8_t samplingTimeLSB,
1187 		uint8_t samplingTimeMSB)
1188 {
1189 	struct ipmi_rs * rsp;
1190 	struct ipmi_rq req;
1191 	uint8_t msg_data[7]; /* number of request data bytes */
1192 
1193 	msg_data[0] = IPMI_DCMI; /* Group Extension Identification */
1194 	msg_data[1] = entityID; /* Inlet Temperature DCMI ID*/
1195 	msg_data[2] = entityInst; /* Entity Instance */
1196 	/* persistance and actions or disabled if no actions */
1197 	msg_data[3] = (((persistanceFlag ? 1 : 0) << 7) |
1198 			((actionHardPowerOff? 1 : 0) << 6) |
1199 			((actionLogToSEL ? 1 : 0) << 5));
1200 	msg_data[4] = tempLimit;
1201 	msg_data[5] = samplingTimeLSB;
1202 	msg_data[6] = samplingTimeMSB;
1203 
1204 	memset(&req, 0, sizeof(req));
1205 	req.msg.netfn = IPMI_NETFN_DCGRP;
1206 	/* Get thermal policy reading */
1207 	req.msg.cmd = IPMI_DCMI_SETTERMALLIMIT;
1208 	req.msg.data = msg_data; /* msg_data above */
1209 	/* how many times does req.msg.data need to read */
1210 	req.msg.data_len = 7;
1211 
1212 	rsp = intf->sendrecv(intf, &req);
1213 	if (chk_rsp(rsp)) {
1214 		return -1;
1215 	}
1216 	/* rsp->data[0] is equal to response data byte 2 in spec */
1217 	printf("\nThermal policy %d for %0Xh entity successfully set.\n\n",
1218 			entityInst, entityID);
1219 	return 0;
1220 }
1221 
1222 /* This is Get Temperature Readings Command
1223  *
1224  * returns ipmi response structure
1225  *
1226  * @intf:   ipmi interface handler
1227  */
1228 struct ipmi_rs *
1229 ipmi_dcmi_get_temp_readings(struct ipmi_intf * intf,
1230 		uint8_t entityID,
1231 		uint8_t entityInst,
1232 		uint8_t entityInstStart)
1233 {
1234 	struct ipmi_rq req;
1235 	uint8_t msg_data[5]; /* number of request data bytes */
1236 
1237 	msg_data[0] = IPMI_DCMI; /* Group Extension Identification */
1238 	msg_data[1] = 0x01; /* Sensor type */
1239 	msg_data[2] = entityID; /* Entity Instance */
1240 	msg_data[3] = entityInst;
1241 	msg_data[4] = entityInstStart;
1242 
1243 	memset(&req, 0, sizeof(req));
1244 	req.msg.netfn = IPMI_NETFN_DCGRP;
1245 	req.msg.cmd = IPMI_DCMI_GETTEMPRED; /* Get thermal policy reading */
1246 	req.msg.data = msg_data; /* msg_data above */
1247 	/* how many times does req.msg.data need to read */
1248 	req.msg.data_len = 5;
1249 	return intf->sendrecv(intf, &req);
1250 }
1251 
1252 static int
1253 ipmi_dcmi_prnt_get_temp_readings(struct ipmi_intf * intf)
1254 {
1255 	struct ipmi_rs * rsp;
1256 	int i,j, tota_inst, get_inst, offset = 0;
1257 	/* Print sensor description */
1258 	printf("\n\tEntity ID\t\t\tEntity Instance\t   Temp. Readings");
1259 	for (i = 0; dcmi_temp_read_vals[i].str != NULL; i++) {
1260 		/* get all of the information about this sensor */
1261 		rsp = ipmi_dcmi_get_temp_readings(intf,
1262 				dcmi_temp_read_vals[i].val, 0, 0);
1263 		if (chk_rsp(rsp)) {
1264 			continue;
1265 		}
1266 		/* Total number of available instances for the Entity ID */
1267 		offset = 0;
1268 		tota_inst = rsp->data[1];
1269 		while (tota_inst > 0) {
1270 			get_inst = ((tota_inst / DCMI_MAX_BYTE_TEMP_READ_SIZE) ?
1271 					DCMI_MAX_BYTE_TEMP_READ_SIZE :
1272 					(tota_inst % DCMI_MAX_BYTE_TEMP_READ_SIZE));
1273 			rsp = ipmi_dcmi_get_temp_readings(intf,
1274 					dcmi_temp_read_vals[i].val, offset, 0);
1275 			if (chk_rsp(rsp)) {
1276 				continue;
1277 			}
1278 			/* Number of sets of Temperature Data in this
1279 			 * response (Max 8 per response)
1280 			 */
1281 			for (j=0; j < rsp->data[2]*2; j=j+2) {
1282 				/* Print Instance temperature info */
1283 				printf("\n%s",dcmi_temp_read_vals[i].desc);
1284 				printf("\t\t%i\t\t%c%i C", rsp->data[j+4],
1285 						((rsp->data[j+3]) >> 7) ?
1286 						'-' : '+', (rsp->data[j+3] & 127));
1287 			}
1288 			offset += get_inst;
1289 			tota_inst -= get_inst;
1290 		}
1291 	}
1292 	return 0;
1293 }
1294 
1295 /* This is Get DCMI Config Parameters Command
1296  *
1297  * returns ipmi response structure
1298  *
1299  * @intf:   ipmi interface handler
1300  */
1301 struct ipmi_rs *
1302 ipmi_dcmi_getconfparam(struct ipmi_intf * intf, int param_selector)
1303 {
1304 	struct ipmi_rq req;
1305 	uint8_t msg_data[3]; /* number of request data bytes */
1306 
1307 	msg_data[0] = IPMI_DCMI; /* Group Extension Identification */
1308 	msg_data[1] = param_selector; /* Parameter selector */
1309 	/* Set Selector. Selects a given set of parameters under a given Parameter
1310 	 * selector value. 00h if parameter doesn't use a Set Selector.
1311 	 */
1312 	msg_data[2] = 0x00;
1313 
1314 	memset(&req, 0, sizeof(req));
1315 	req.msg.netfn = IPMI_NETFN_DCGRP;
1316 	req.msg.cmd = IPMI_DCMI_GETCONFPARAM; /* Get DCMI Config Parameters */
1317 	req.msg.data = msg_data; /* Contents above */
1318 	/* how many times does req.msg.data need to read */
1319 	req.msg.data_len = 3;
1320 	return intf->sendrecv(intf, &req);
1321 }
1322 
1323 static int
1324 ipmi_dcmi_prnt_getconfparam(struct ipmi_intf * intf)
1325 {
1326 	struct ipmi_rs * rsp;
1327 	const int dcmi_conf_params = 5;
1328 	int param_selector;
1329 	uint16_t tmp_value = 0;
1330 	/* We are not interested in parameter 1 which always will return 0 */
1331 	for (param_selector = 2 ; param_selector <= dcmi_conf_params;
1332 			param_selector++) {
1333 		rsp = ipmi_dcmi_getconfparam(intf, param_selector);
1334 		if (chk_rsp(rsp)) {
1335 			return -1;
1336 		}
1337 		/* Time to print what we have got */
1338 		switch(param_selector) {
1339 		case 2:
1340 			tmp_value = (rsp->data[4])& 1;
1341 			printf("\n\tDHCP Discovery method\t: ");
1342 			printf("\n\t\tManagement Controller ID String is %s",
1343 					tmp_value ? "enabled" : "disabled");
1344 			printf("\n\t\tVendor class identifier DCMI IANA and Vendor class-specific Informationa are %s",
1345 					((rsp->data[4])& 2) ? "enabled" : "disabled" );
1346 			break;
1347 		case 3:
1348 			printf("\n\tInitial timeout interval\t: %i seconds",
1349 					rsp->data[4]);
1350 			break;
1351 		case 4:
1352 			printf("\n\tServer contact timeout interval\t: %i seconds",
1353 					rsp->data[4] + (rsp->data[5]<<8));
1354 			break;
1355 		case 5:
1356 			printf("\n\tServer contact retry interval\t: %i seconds",
1357 					rsp->data[4] + (rsp->data[5] << 8));
1358 			break;
1359 		default:
1360 			printf("\n\tConfiguration Parameter not supported.");
1361 		}
1362 	}
1363 	return 0;
1364 }
1365 
1366 /* This is Set DCMI Config Parameters Command
1367  *
1368  * returns ipmi response structure
1369  *
1370  * @intf:   ipmi interface handler
1371  */
1372 struct ipmi_rs *
1373 ipmi_dcmi_setconfparam(struct ipmi_intf * intf, uint8_t param_selector,
1374 		uint16_t value)
1375 {
1376 	struct ipmi_rq req;
1377 	uint8_t msg_data[5]; /* number of request data bytes */
1378 
1379 	msg_data[0] = IPMI_DCMI; /* Group Extension Identification */
1380 	msg_data[1] = param_selector; /* Parameter selector */
1381 	/* Set Selector (use 00h for parameters that only have one set). */
1382 	msg_data[2] = 0x00;
1383 
1384 	if (param_selector > 3) {
1385 		/* One bite more */
1386 		msg_data[3] = value & 0xFF;
1387 		msg_data[4] = value >> 8;
1388 	} else {
1389 		msg_data[3] = value;
1390 	}
1391 
1392 	memset(&req, 0, sizeof(req));
1393 	req.msg.netfn = IPMI_NETFN_DCGRP;
1394 	req.msg.cmd = IPMI_DCMI_SETCONFPARAM; /* Set DCMI Config Parameters */
1395 	req.msg.data = msg_data; /* Contents above */
1396 	if (param_selector > 3) {
1397 		/* One bite more */
1398 		/* how many times does req.msg.data need to read */
1399 		req.msg.data_len = 5;
1400 	} else {
1401 		/* how many times does req.msg.data need to read */
1402 		req.msg.data_len = 4;
1403 	}
1404 	return intf->sendrecv(intf, &req);
1405 }
1406 
1407 /*  Power Management get limit ipmi response
1408  *
1409  * This function returns the currently set power management settings as an
1410  * ipmi response structure.  The reason it returns in the rsp struct is so
1411  * that it can be used in the set limit [slimit()] function to populate
1412  * un-changed or un-edited values.
1413  *
1414  * returns ipmi response structure
1415  *
1416  * @intf:   ipmi interface handler
1417  */
1418 struct ipmi_rs * ipmi_dcmi_pwr_glimit(struct ipmi_intf * intf)
1419 {
1420 	struct ipmi_rq req;
1421 	uint8_t msg_data[3]; /* number of request data bytes */
1422 
1423 	msg_data[0] = IPMI_DCMI; /* Group Extension Identification */
1424 	msg_data[1] = 0x00; /* reserved */
1425 	msg_data[2] = 0x00; /* reserved */
1426 
1427 	memset(&req, 0, sizeof(req));
1428 	req.msg.netfn = IPMI_NETFN_DCGRP;
1429 	req.msg.cmd = IPMI_DCMI_GETLMT; /* Get power limit */
1430 	req.msg.data = msg_data; /* Contents above */
1431 	/* how many times does req.msg.data need to read */
1432 	req.msg.data_len = 3;
1433 
1434 	return intf->sendrecv(intf, &req);
1435 }
1436 /* end Power Management get limit response */
1437 
1438 /*  Power Management print the get limit command
1439  *
1440  * This function calls the get limit function that returns an ipmi response.
1441  *
1442  * returns 0 else 1 with error
1443  * @intf:   ipmi interface handler
1444  */
1445 static int
1446 ipmi_dcmi_pwr_prnt_glimit(struct ipmi_intf * intf)
1447 {
1448 	struct ipmi_rs * rsp;
1449 	struct power_limit val;
1450 	uint8_t realCc = 0xff;
1451 
1452 	rsp = ipmi_dcmi_pwr_glimit(intf);
1453 	/* rsp can be a null so check response before any operation
1454 	 * on it to avoid sig segv
1455 	 */
1456 	if (rsp != NULL) {
1457 		realCc = rsp->ccode;
1458 		GOOD_PWR_GLIMIT_CCODE(rsp->ccode);
1459 	}
1460 	if (chk_rsp(rsp)) {
1461 		return -1;
1462 	}
1463 	/* rsp->data[0] is equal to response data byte 2 in spec */
1464 	/* printf("Group Extension Identification: %02x\n", rsp->data[0]); */
1465 	memcpy(&val, rsp->data, sizeof (val));
1466 	printf("\n    Current Limit State: %s\n",
1467 			(realCc == 0) ?
1468 			"Power Limit Active" : "No Active Power Limit");
1469 	printf("    Exception actions:   %s\n",
1470 			val2str2(val.action, dcmi_pwrmgmt_get_action_vals));
1471 	printf("    Power Limit:         %i Watts\n", val.limit);
1472 	printf("    Correction time:     %i milliseconds\n", val.correction);
1473 	printf("    Sampling period:     %i seconds\n", val.sample);
1474 	printf("\n");
1475 	return 0;
1476 }
1477 /* end print get limit */
1478 
1479 /*  Power Management set limit
1480  *
1481  * Undocumented bounds:
1482  * Power limit: 0 - 0xFFFF
1483  * Correction period 5750ms to 28751ms or 0x1676 to 0x704F
1484  * sample period: 3 sec to 65 sec and 69+
1485  *
1486  * @intf:    ipmi interface handler
1487  * @option:  Power option to change
1488  * @value:   Value of the desired change
1489  */
1490 static int
1491 ipmi_dcmi_pwr_slimit(struct ipmi_intf * intf, const char * option,
1492 		const char * value)
1493 {
1494 	struct ipmi_rs * rsp; /* ipmi response */
1495 	struct ipmi_rq req; /* ipmi request (to send) */
1496 	struct power_limit val;
1497 	uint8_t msg_data[15]; /* number of request data bytes */
1498 	uint32_t lvalue = 0;
1499 	int i;
1500 
1501 	rsp = ipmi_dcmi_pwr_glimit(intf); /* get the power limit settings */
1502 # if 0
1503 	{
1504 		unsigned char counter = 0;
1505 		printf("DATA (%d): ", rsp->data_len);
1506 		for(counter = 0; counter < rsp->data_len; counter ++) {
1507 			printf("%02X ", rsp->data[counter]);
1508 		}
1509 		printf("\n");
1510 	}
1511 # endif
1512 	/* rsp can be a null so check response before any operation on it to
1513 	 * avoid sig segv
1514 	 */
1515 	if (rsp != NULL) {
1516 		GOOD_PWR_GLIMIT_CCODE(rsp->ccode);
1517 	}
1518 	if (chk_rsp(rsp)) {
1519 		return -1;
1520 	}
1521 	memcpy(&val, rsp->data, sizeof (val));
1522 	/* same as above; sets the values of the val struct
1523 	 * DCMI group ID *
1524 	 * val.grp_id = rsp->data[0];
1525 	 * exception action *
1526 	 * val.action = rsp->data[3]; *
1527 	 *
1528 	 * power limit in Watts *
1529 	 * store 16 bits of the rsp from the 4th entity *
1530 	 * val.limit = *(uint16_t*)(&rsp->data[4]);
1531 	 * correction period in mS *
1532 	 * store 32 bits of the rsp from the 6th entity *
1533 	 * val.correction = *(uint32_t*)(&rsp->data[6]);
1534 	 * store 16 bits of the rsp from the 12th entity *
1535 	 * sample period in seconds *
1536 	 * val.sample = *(uint16_t*)(&rsp->data[12]);
1537 	 */
1538 	lprintf(LOG_INFO,
1539 			"DCMI IN  Limit=%d Correction=%d Action=%d Sample=%d\n",
1540 			val.limit, val.correction, val.action, val.sample);
1541 	switch (str2val2(option, dcmi_pwrmgmt_set_usage_vals)) {
1542 	case 0x00:
1543 		/* action */
1544 		switch (str2val2(value, dcmi_pwrmgmt_action_vals)) {
1545 		case 0x00:
1546 			/* no_action */
1547 			val.action = 0;
1548 			break;
1549 		case 0x01:
1550 			/* power_off */
1551 			val.action = 1;
1552 			break;
1553 		case 0x02:
1554 			/* OEM reserved action */
1555 			val.action = 0x02;
1556 			break;
1557 		case 0x03:
1558 			/* OEM reserved action */
1559 			val.action = 0x03;
1560 			break;
1561 		case 0x04:
1562 			/* OEM reserved action */
1563 			val.action = 0x04;
1564 			break;
1565 		case 0x05:
1566 			/* OEM reserved action */
1567 			val.action = 0x05;
1568 			break;
1569 		case 0x06:
1570 			/* OEM reserved action */
1571 			val.action = 0x06;
1572 			break;
1573 		case 0x07:
1574 			/* OEM reserved action */
1575 			val.action = 0x07;
1576 			break;
1577 		case 0x08:
1578 			/* OEM reserved action */
1579 			val.action = 0x08;
1580 			break;
1581 		case 0x09:
1582 			/* OEM reserved action */
1583 			val.action = 0x09;
1584 			break;
1585 		case 0x0a:
1586 			/* OEM reserved action */
1587 			val.action = 0x0a;
1588 			break;
1589 		case 0x0b:
1590 			/* OEM reserved action */
1591 			val.action = 0x0b;
1592 			break;
1593 		case 0x0c:
1594 			/* OEM reserved action */
1595 			val.action = 0x0c;
1596 			break;
1597 		case 0x0d:
1598 			/* OEM reserved action */
1599 			val.action = 0x0d;
1600 			break;
1601 		case 0x0e:
1602 			/* OEM reserved action */
1603 			val.action = 0x0e;
1604 			break;
1605 		case 0x0f:
1606 			/* OEM reserved action */
1607 			val.action = 0x0f;
1608 			break;
1609 		case 0x10:
1610 			/* OEM reserved action */
1611 			val.action = 0x10;
1612 			break;
1613 		case 0x11:
1614 			/* sel_logging*/
1615 			val.action = 0x11;
1616 			break;
1617 		case 0xFF:
1618 			/* error - not a string we knew what to do with */
1619 			lprintf(LOG_ERR, "Given %s '%s' is invalid.",
1620 					option, value);
1621 			return -1;
1622 		}
1623 		break;
1624 	case 0x01:
1625 		/* limit */
1626 		if (str2uint(value, &lvalue) != 0) {
1627 			lprintf(LOG_ERR, "Given %s '%s' is invalid.",
1628 					option, value);
1629 			return (-1);
1630 		}
1631 		val.limit = *(uint16_t*)(&lvalue);
1632 		break;
1633 	case 0x02:
1634 		/* correction */
1635 		if (str2uint(value, &lvalue) != 0) {
1636 			lprintf(LOG_ERR, "Given %s '%s' is invalid.",
1637 					option, value);
1638 			return (-1);
1639 		}
1640 		val.correction = *(uint32_t*)(&lvalue);
1641 		break;
1642 	case 0x03:
1643 		/* sample */
1644 		if (str2uint(value, &lvalue) != 0) {
1645 			lprintf(LOG_ERR, "Given %s '%s' is invalid.",
1646 					option, value);
1647 			return (-1);
1648 		}
1649 		val.sample = *(uint16_t*)(&lvalue);
1650 		break;
1651 	case 0xff:
1652 		/* no valid options */
1653 		return -1;
1654 	}
1655 	lprintf(LOG_INFO, "DCMI OUT Limit=%d Correction=%d Action=%d Sample=%d\n", val.limit, val.correction, val.action, val.sample);
1656 
1657 	msg_data[0] = val.grp_id; /* Group Extension Identification */
1658 	msg_data[1] = 0x00; /* reserved */
1659 	msg_data[2] = 0x00; /* reserved */
1660 	msg_data[3] = 0x00; /* reserved */
1661 	msg_data[4] = val.action; /* exception action; 0x00 disables it */
1662 
1663 	/* fill msg_data[5] with the first 16 bits of val.limit */
1664 	*(uint16_t*)(&msg_data[5]) = val.limit;
1665 	/* msg_data[5] = 0xFF;
1666 	 * msg_data[6] = 0xFF;
1667 	 */
1668 	/* fill msg_data[7] with the first 32 bits of val.correction */
1669 	*(uint32_t*)(&msg_data[7]) = val.correction;
1670 	/* msg_data[7] = 0x76;
1671 	 * msg_data[8] = 0x16;
1672 	 * msg_data[9] = 0x00;
1673 	 * msg_data[10] = 0x00;
1674 	 */
1675 	msg_data[11] = 0x00; /* reserved */
1676 	msg_data[12] = 0x00; /* reserved */
1677 	/* fill msg_data[7] with the first 16 bits of val.sample */
1678 	*(uint16_t*)(&msg_data[13]) = val.sample;
1679 	/* msg_data[13] = 0x03; */
1680 	memset(&req, 0, sizeof(req));
1681 	req.msg.netfn = IPMI_NETFN_DCGRP;
1682 	req.msg.cmd = IPMI_DCMI_SETLMT; /* Set power limit */
1683 	req.msg.data = msg_data; /* Contents above */
1684 	/* how many times does req.msg.data need to read */
1685 	req.msg.data_len = 15;
1686 
1687 	rsp = intf->sendrecv(intf, &req);
1688 
1689 	if (chk_rsp(rsp)) {
1690 		return -1;
1691 	}
1692 	return 0;
1693 }
1694 /* end Power Management set limit */
1695 
1696 /*  Power Management activate deactivate
1697  *
1698  * @intf:    ipmi interface handler
1699  * @option:  uint8_t - 0 to deactivate or 1 to activate
1700  */
1701 static int
1702 ipmi_dcmi_pwr_actdeact(struct ipmi_intf * intf, uint8_t option)
1703 {
1704 	struct ipmi_rs * rsp;
1705 	struct ipmi_rq req;
1706 	uint8_t msg_data[4]; /* number of request data bytes */
1707 
1708 	msg_data[0] = IPMI_DCMI; /* Group Extension Identification */
1709 	msg_data[1] = option; /* 0 = Deactivate 1 = Activate */
1710 	msg_data[2] = 0x00; /* reserved */
1711 	msg_data[3] = 0x00; /* reserved */
1712 
1713 	memset(&req, 0, sizeof(req));
1714 	req.msg.netfn = IPMI_NETFN_DCGRP;
1715 	req.msg.cmd = IPMI_DCMI_PWRACT; /* Act-deactivate power limit */
1716 	req.msg.data = msg_data; /* Contents above */
1717 	req.msg.data_len = 4; /* how mant times does req.msg.data need to read */
1718 
1719 	rsp = intf->sendrecv(intf, &req);
1720 	if (chk_rsp(rsp)) {
1721 		return -1;
1722 	}
1723 	printf("\n    Power limit successfully ");
1724 	if (option == 0x00) {
1725 		printf("deactivated");
1726 	} else {
1727 		printf("activated");
1728 	}
1729 	printf("\n");
1730 	return 0;
1731 }
1732 /* end power management activate/deactivate */
1733 
1734 /*  main
1735  *
1736  * @intf:   dcmi interface handler
1737  * @argc:   argument count
1738  * @argv:   argument vector
1739  */
1740 int
1741 ipmi_dcmi_main(struct ipmi_intf * intf, int argc, char **argv)
1742 {
1743 	int rc = 0;
1744 	uint8_t ctl = 0;
1745 	int i, ii, instances;
1746 	struct ipmi_rs *rsp;
1747 
1748 	if ((argc == 0) || (strncmp(argv[0], "help", 4) == 0)) {
1749 		print_strs(dcmi_cmd_vals,
1750 				"Data Center Management Interface commands",
1751 				-1, 0);
1752 		return -1;
1753 	}
1754 	/* start the cmd requested */
1755 	switch (str2val2(argv[0], dcmi_cmd_vals)) {
1756 	case 0x00:
1757 		/* discover capabilities*/
1758 		for (i = 1; dcmi_capable_vals[i-1].str != NULL; i++) {
1759 			if (ipmi_dcmi_prnt_getcapabilities(intf, i) < 0) {
1760 				printf("Error discovering %s capabilities!\n",
1761 						val2str2(i, dcmi_capable_vals));
1762 				return -1;
1763 			}
1764 		}
1765 		break;
1766 	case 0x01:
1767 		/* power */
1768 		argv++;
1769 		if (argv[0] == NULL) {
1770 			print_strs(dcmi_pwrmgmt_vals, "power <command>",
1771 					-1, 0);
1772 			return -1;
1773 		}
1774 		/* power management */
1775 		switch (str2val2(argv[0], dcmi_pwrmgmt_vals)) {
1776 		case 0x00:
1777 			/* get reading */
1778 			rc = ipmi_dcmi_pwr_rd(intf);
1779 			break;
1780 		case 0x01:
1781 			/* get limit */
1782 			/* because the get limit function is also used to
1783 			 * populate unchanged values for the set limit
1784 			 * command it returns an ipmi response structure
1785 			 */
1786 			rc = ipmi_dcmi_pwr_prnt_glimit(intf);
1787 			break;
1788 		case 0x02:
1789 			/* set limit */
1790 			if (argc < 4) {
1791 				print_strs(dcmi_pwrmgmt_set_usage_vals,
1792 						"set_limit <parameter> <value>",
1793 						-1, 0);
1794 				return -1;
1795 			}
1796 			if ( argc == 10) {
1797 				/* Let`s initialize dcmi power parameters */
1798 				struct ipmi_rq req;
1799 				uint8_t data[256];
1800 				uint16_t sample = 0;
1801 				uint16_t limit = 0;
1802 				uint32_t correction = 0;
1803 
1804 				memset(data, 0, sizeof(data));
1805 				memset(&req, 0, sizeof(req));
1806 
1807 				req.msg.netfn = IPMI_NETFN_DCGRP;
1808 				req.msg.lun = 0x00;
1809 				req.msg.cmd = IPMI_DCMI_SETLMT; /* Set power limit */
1810 				req.msg.data = data; /* Contents above */
1811 				req.msg.data_len =  15;
1812 
1813 				data[0] = IPMI_DCMI; /* Group Extension Identification */
1814 				data[1] = 0x0;  /* reserved */
1815 				data[2] = 0x0;  /* reserved */
1816 				data[3] = 0x0;  /* reserved */
1817 
1818 				/* action */
1819 				switch (str2val2(argv[2], dcmi_pwrmgmt_action_vals)) {
1820 				case 0x00:
1821 					/* no_action */
1822 					data[4] = 0x00;
1823 					break;
1824 				case 0x01:
1825 					/* power_off */
1826 					data[4] = 0x01;
1827 					break;
1828 				case 0x11:
1829 					/* sel_logging*/
1830 					data[4] = 0x11;
1831 					break;
1832 				case 0xFF:
1833 					/* error - not a string we knew what to do with */
1834 					lprintf(LOG_ERR, "Given Action '%s' is invalid.",
1835 							argv[2]);
1836 					return -1;
1837 				}
1838 				/* limit */
1839 				if (str2ushort(argv[4], &limit) != 0) {
1840 					lprintf(LOG_ERR,
1841 							"Given Limit '%s' is invalid.",
1842 							argv[4]);
1843 					return (-1);
1844 				}
1845 				data[5] = limit >> 0;
1846 				data[6] = limit >> 8;
1847 				/* correction */
1848 				if (str2uint(argv[6], &correction) != 0) {
1849 					lprintf(LOG_ERR,
1850 							"Given Correction '%s' is invalid.",
1851 							argv[6]);
1852 					return (-1);
1853 				}
1854 				data[7] = correction >> 0;
1855 				data[8] = correction >> 8;
1856 				data[9] = correction >> 16;
1857 				data[10] = correction >> 24;
1858 				data[11] = 0x00;  /* reserved */
1859 				data[12] = 0x00;  /* reserved */
1860 				/* sample */
1861 				if (str2ushort(argv[8], &sample) != 0) {
1862 					lprintf(LOG_ERR,
1863 							"Given Sample '%s' is invalid.",
1864 							argv[8]);
1865 					return (-1);
1866 				}
1867 				data[13] = sample >> 0;
1868 				data[14] = sample >> 8;
1869 
1870 				rsp = intf->sendrecv(intf, &req);
1871 				if (chk_rsp(rsp)) {
1872 					return -1;
1873 				}
1874 			} else {
1875 				/* loop through each parameter and value until we have neither */
1876 				while ((argv[1] != NULL) && (argv[2] != NULL)) {
1877 					rc = ipmi_dcmi_pwr_slimit(intf, argv[1], argv[2]);
1878 					/* catch any error that the set limit function returned */
1879 					if (rc > 0) {
1880 						print_strs(dcmi_pwrmgmt_set_usage_vals,
1881 								"set_limit <parameter> <value>", -1, 0);
1882 						return -1;
1883 					}
1884 					/* the first argument is the command and the second is the
1885 					 * value.  Move argv two places; what is now 3 will be 1
1886 					 */
1887 					argv+=2;
1888 				}
1889 			}
1890 			rc = ipmi_dcmi_pwr_prnt_glimit(intf);
1891 			break;
1892 		case 0x03:
1893 			/* activate */
1894 			rc = ipmi_dcmi_pwr_actdeact(intf, 1);
1895 			break;
1896 		case 0x04:
1897 			/* deactivate */
1898 			rc = ipmi_dcmi_pwr_actdeact(intf, 0);
1899 			break;
1900 		default:
1901 			/* no valid options */
1902 			print_strs(dcmi_pwrmgmt_vals,
1903 					"power <command>", -1, 0);
1904 			break;
1905 		}
1906 		/* power mgmt end */
1907 		break;
1908 		/* end power command */
1909 	case 0x02:
1910 		/* sensor print */
1911 		/* Look for each item in the dcmi_discvry_snsr_vals struct
1912 		 * and if it exists, print the sdr record id(s) for it.
1913 		 * Use the val from each one as the sensor number.
1914 		 */
1915 		for (i = 0; dcmi_discvry_snsr_vals[i].str != NULL; i++) {
1916 			/* get all of the information about this sensor */
1917 			rc = ipmi_dcmi_prnt_discvry_snsr(intf,
1918 					dcmi_discvry_snsr_vals[i].val);
1919 		}
1920 		break;
1921 		/* end sensor print */
1922 	case 0x03:
1923 		/* asset tag */
1924 		if(ipmi_dcmi_prnt_getassettag(intf) < 0) {
1925 			lprintf(LOG_ERR, "Error getting asset tag!");
1926 			return -1;
1927 		}
1928 		break;
1929 		/* end asset tag */
1930 	case 0x04:
1931 	{
1932 		/* set asset tag */
1933 		if (argc == 1 ) {
1934 			print_strs(dcmi_cmd_vals,
1935 					"Data Center Management Interface commands",
1936 					-1, 0);
1937 			return -1;
1938 		}
1939 		if (ipmi_dcmi_prnt_setassettag(intf, argv[1]) < 0) {
1940 			lprintf(LOG_ERR, "\nError setting asset tag!");
1941 			return -1;
1942 		}
1943 		break;
1944 	}
1945 	/* end set asset tag */
1946 	case 0x05:
1947 		/* get management controller identifier string */
1948 		if (ipmi_dcmi_prnt_getmngctrlids(intf) < 0) {
1949 			lprintf(LOG_ERR,
1950 					"Error getting management controller identifier string!");
1951 			return -1;
1952 		}
1953 		break;
1954 		/* end get management controller identifier string */
1955 	case 0x06:
1956 	{
1957 		/* set management controller identifier string */
1958 		if (argc == 1 ) {
1959 			print_strs(dcmi_cmd_vals,
1960 					"Data Center Management Interface commands",
1961 					-1, 0);
1962 			return -1;
1963 		}
1964 		if (ipmi_dcmi_prnt_setmngctrlids(intf, argv[1]) < 0) {
1965 			lprintf(LOG_ERR,
1966 					"Error setting management controller identifier string!");
1967 			return -1;
1968 		}
1969 		break;
1970 	}
1971 	/* end set management controller identifier string */
1972 	case 0x07:
1973 	{
1974 		uint8_t entityID = 0;
1975 		uint8_t entityInst = 0;
1976 		uint8_t persistanceFlag;
1977 		uint8_t actionHardPowerOff;
1978 		uint8_t actionLogToSEL;
1979 		uint8_t tempLimit = 0;
1980 		uint8_t samplingTimeLSB;
1981 		uint8_t samplingTimeMSB;
1982 		uint16_t samplingTime = 0;
1983 		/* Thermal policy get/set */
1984 		/* dcmitool dcmi thermalpolicy get */
1985 		switch (str2val2(argv[1], dcmi_thermalpolicy_vals)) {
1986 		case 0x00:
1987 			if (argc < 4) {
1988 				lprintf(LOG_NOTICE, "Get <entityID> <instanceID>");
1989 				return -1;
1990 			}
1991 			if (str2uchar(argv[2], &entityID) != 0) {
1992 				lprintf(LOG_ERR,
1993 						"Given Entity ID '%s' is invalid.",
1994 						argv[2]);
1995 				return (-1);
1996 			}
1997 			if (str2uchar(argv[3], &entityInst) != 0) {
1998 				lprintf(LOG_ERR,
1999 						"Given Instance ID '%s' is invalid.",
2000 						argv[3]);
2001 				return (-1);
2002 			}
2003 			rc = ipmi_dcmi_getthermalpolicy(intf,  entityID, entityInst);
2004 			break;
2005 		case 0x01:
2006 			if (argc < 4) {
2007 				lprintf(LOG_NOTICE, "Set <entityID> <instanceID>");
2008 				return -1;
2009 			} else if (argc < 9) {
2010 				print_strs(dcmi_thermalpolicy_set_parameters_vals,
2011 						"Set thermalpolicy instance parameters: "
2012 						"<volatile/nonvolatile/disabled> "
2013 						"<poweroff/nopoweroff/disabled> "
2014 						"<sel/nosel/disabled> <templimitByte> <exceptionTime>",
2015 						-1, 0);
2016 				return -1;
2017 			}
2018 			if (str2uchar(argv[2], &entityID) != 0) {
2019 				lprintf(LOG_ERR,
2020 						"Given Entity ID '%s' is invalid.",
2021 						argv[2]);
2022 				return (-1);
2023 			}
2024 			if (str2uchar(argv[3], &entityInst) != 0) {
2025 				lprintf(LOG_ERR,
2026 						"Given Instance ID '%s' is invalid.",
2027 						argv[3]);
2028 				return (-1);
2029 			}
2030 			persistanceFlag = (uint8_t) str2val2(argv[4], dcmi_thermalpolicy_set_parameters_vals);
2031 			actionHardPowerOff = (uint8_t) str2val2(argv[5], dcmi_thermalpolicy_set_parameters_vals);
2032 			actionLogToSEL = (uint8_t) str2val2(argv[6], dcmi_thermalpolicy_set_parameters_vals);
2033 			if (str2uchar(argv[7], &tempLimit) != 0) {
2034 				lprintf(LOG_ERR,
2035 						"Given Temp Limit '%s' is invalid.",
2036 						argv[7]);
2037 				return (-1);
2038 			}
2039 			if (str2ushort(argv[8], &samplingTime) != 0) {
2040 				lprintf(LOG_ERR,
2041 						"Given Sampling Time '%s' is invalid.",
2042 						argv[8]);
2043 				return (-1);
2044 			}
2045 			samplingTimeLSB =  (samplingTime & 0xFF);
2046 			samplingTimeMSB = ((samplingTime & 0xFF00) >> 8);
2047 
2048 			rc = ipmi_dcmi_setthermalpolicy(intf,
2049 					entityID,
2050 					entityInst,
2051 					persistanceFlag,
2052 					actionHardPowerOff,
2053 					actionLogToSEL,
2054 					tempLimit,
2055 					samplingTimeLSB,
2056 					samplingTimeMSB);
2057 
2058 			break;
2059 		default:
2060 			print_strs(dcmi_thermalpolicy_vals,
2061 					"thermalpolicy <command>",
2062 					-1, 0);
2063 			return -1;
2064 		}
2065 		break;
2066 	}
2067 	case 0x08:
2068 		if(ipmi_dcmi_prnt_get_temp_readings(intf) < 0 ) {
2069 			lprintf(LOG_ERR,
2070 					"Error get temperature readings!");
2071 		}
2072 		break;
2073 	case 0x09:
2074 		if(ipmi_dcmi_prnt_getconfparam(intf) < 0 ) {
2075 			lprintf(LOG_ERR,
2076 					"Error Get DCMI Configuration Parameters!");
2077 		};
2078 		break;
2079 	case 0x0A:
2080 	{
2081 		switch (argc) {
2082 		case 2:
2083 			if (strncmp(argv[1], "activate_dhcp", 13) != 0) {
2084 				print_strs( dcmi_conf_param_vals,
2085 						"DCMI Configuration Parameters",
2086 						-1, 0);
2087 				return -1;
2088 			}
2089 			break;
2090 		default:
2091 			if (argc != 3 || strncmp(argv[1], "help", 4) == 0) {
2092 				print_strs(dcmi_conf_param_vals,
2093 						"DCMI Configuration Parameters",
2094 						-1, 0);
2095 				return -1;
2096 			}
2097 		}
2098 		if (strncmp(argv[1], "activate_dhcp", 13) == 0) {
2099 			rsp = ipmi_dcmi_setconfparam(intf, 1, 1);
2100 		} else {
2101 			uint16_t tmp_val = 0;
2102 			if (str2ushort(argv[2], &tmp_val) != 0) {
2103 				lprintf(LOG_ERR,
2104 						"Given %s '%s' is invalid.",
2105 						argv[1], argv[2]);
2106 				return (-1);
2107 			}
2108 			rsp = ipmi_dcmi_setconfparam(intf,
2109 					str2val2(argv[1], dcmi_conf_param_vals),
2110 					tmp_val);
2111 		}
2112 		if (chk_rsp(rsp)) {
2113 			lprintf(LOG_ERR,
2114 					"Error Set DCMI Configuration Parameters!");
2115 		}
2116 		break;
2117 	}
2118 	case 0x0B:
2119 	{
2120 		if (intf->session == NULL) {
2121 			lprintf(LOG_ERR,
2122 					"\nOOB discovery is available only via RMCP interface.");
2123 			return -1;
2124 		}
2125 		if(ipmi_dcmi_prnt_oobDiscover(intf) < 0) {
2126 			lprintf(LOG_ERR, "\nOOB discovering capabilities failed.");
2127 			return -1;
2128 		}
2129 		break;
2130 	}
2131 	default:
2132 		/* couldn't detect what the user entered */
2133 		print_strs(dcmi_cmd_vals,
2134 				"Data Center Management Interface commands",
2135 				-1, 0);
2136 		return -1;
2137 		break;
2138 	}
2139 	printf("\n");
2140 	return 0;
2141 }
2142 
2143 /* Display DCMI sensor information
2144  * Uses the ipmi_sdr_get_next_header to read SDR header and compare to the
2145  * target Record ID. Then either ipmi_sensor_print_full or
2146  * ipmi_sensor_print_compact is called to print the data
2147  *
2148  * @intf:   ipmi interface handler
2149  * @rec_id: target Record ID
2150  */
2151 static int
2152 ipmi_print_sensor_info(struct ipmi_intf *intf, uint16_t rec_id)
2153 {
2154 	struct sdr_get_rs *header;
2155 	struct ipmi_sdr_iterator *itr;
2156 	int rc = 0;
2157 	uint8_t *rec = NULL;
2158 
2159 	itr = ipmi_sdr_start(intf, 0);
2160 	if (itr == NULL) {
2161 		lprintf(LOG_ERR, "Unable to open SDR for reading");
2162 		return (-1);
2163 	}
2164 
2165 	while ((header = ipmi_sdr_get_next_header(intf, itr)) != NULL) {
2166 		if (header->id == rec_id) {
2167 			break;
2168 		}
2169 	}
2170 	if (header == NULL) {
2171 		lprintf(LOG_DEBUG, "header == NULL");
2172 		ipmi_sdr_end(intf, itr);
2173 		return (-1);
2174 	}
2175 	/* yes, we found the SDR for this record ID, now get full record */
2176 	rec = ipmi_sdr_get_record(intf, header, itr);
2177 	if (rec == NULL) {
2178 		lprintf(LOG_DEBUG, "rec == NULL");
2179 		ipmi_sdr_end(intf, itr);
2180 		return (-1);
2181 	}
2182 	if ((header->type == SDR_RECORD_TYPE_FULL_SENSOR) ||
2183 			(header->type == SDR_RECORD_TYPE_COMPACT_SENSOR)) {
2184 		rc = ipmi_sdr_print_rawentry(intf, header->type,
2185 				rec, header->length);
2186 	} else {
2187 		rc = (-1);
2188 	}
2189 	free(rec);
2190 	rec = NULL;
2191 	ipmi_sdr_end(intf, itr);
2192 	return rc;
2193 }
2194