xref: /openbmc/ipmitool/lib/ipmi_dcmi.c (revision 2d79e69f)
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 extern int csv_output;
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 /*
299  * Start of Node Manager Operations
300  */
301 
302 const struct dcmi_cmd dcmi_sampling_vals[] = {
303 	{ 0x05, "5_sec", "" },
304 	{ 0x0f, "15_sec", "" },
305 	{ 0x1E, "30_sec", "" },
306 	{ 0x41, "1_min", "" },
307 	{ 0x43, "3_min", "" },
308 	{ 0x47, "7_min", "" },
309 	{ 0x4F, "15_min", "" },
310 	{ 0x5E, "30_min", "" },
311 	{ 0x81, "1_hour", ""},
312 	{ 0x00, NULL, NULL },
313 };
314 
315 /* Primary Node Manager commands */
316 const struct dcmi_cmd nm_cmd_vals[] = {
317 	{ 0x00, "discover", "Discover Node Manager " },
318 	{ 0x01, "capability", "Get Node Manager Capabilities" },
319 	{ 0x02, "control", "Enable/Disable Policy Control" },
320 	{ 0x03, "policy", "Add/Remove Policies" },
321 	{ 0x04, "statistics", "Get Statistics" },
322 	{ 0x05, "power", "Set Power Draw Range" },
323 	{ 0x06, "suspend", "Set/Get Policy suspend periods" },
324 	{ 0x07, "reset", "Reset Statistics" },
325 	{ 0x08, "alert", "Set/Get/Clear Alert destination" },
326 	{ 0x09, "threshold", "Set/Get Alert Thresholds" },
327 	{ 0xFF, NULL, NULL },
328 };
329 
330 const struct dcmi_cmd nm_ctl_cmds[] = {
331 	{ 0x01, "enable", " <control scope>" },
332 	{ 0x00, "disable", "<control scope>"},
333 	{ 0xFF, NULL, NULL },
334 };
335 
336 const struct dcmi_cmd nm_ctl_domain[] = {
337 	{ 0x00, "global", "" },
338 	{ 0x02, "per_domain", "<platform|CPU|Memory> (default is platform)" },
339 	{ 0x04, "per_policy", "<0-7>" },
340 	{ 0xFF, NULL, NULL },
341 };
342 
343 /* Node Manager Domain codes */
344 const struct dcmi_cmd nm_domain_vals[] = {
345 	{ 0x00, "platform", ""  },
346 	{ 0x01, "CPU", ""  },
347 	{ 0x02, "Memory", "" },
348 	{ 0x03, "protection", "" },
349 	{ 0x04, "I/O", "" },
350 	{ 0xFF, NULL, NULL },
351 };
352 
353 const struct dcmi_cmd nm_version_vals[] = {
354 	{ 0x01, "1.0", "" },
355 	{ 0x02, "1.5", "" },
356 	{ 0x03, "2.0", "" },
357 	{ 0x04, "2.5", "" },
358 	{ 0x05, "3.0", "" },
359 	{ 0xFF, NULL, NULL },
360 };
361 
362 const struct dcmi_cmd nm_capability_opts[] = {
363 	{ 0x01, "domain", "<platform|CPU|Memory> (default is platform)" },
364 	{ 0x02, "inlet", "Inlet temp trigger" },
365 	{ 0x03, "missing", "Missing Power reading trigger" },
366 	{ 0x04, "reset", "Time after Host reset trigger" },
367 	{ 0x05, "boot", "Boot time policy" },
368 	{ 0xFF, NULL, NULL },
369 };
370 
371 const struct  dcmi_cmd nm_policy_type_vals[] = {
372 	{ 0x00, "No trigger, use Power Limit", "" },
373 	{ 0x01, "Inlet temp trigger", "" },
374 	{ 0x02, "Missing Power reading trigger", "" },
375 	{ 0x03, "Time after Host reset trigger", "" },
376 	{ 0x04, "number of cores to disable at boot time", "" },
377 	{ 0xFF, NULL, NULL },
378 };
379 
380 const struct dcmi_cmd nm_stats_opts[] = {
381 	{ 0x01, "domain", "<platform|CPU|Memory> (default is platform)" },
382 	{ 0x02, "policy_id", "<0-7>" },
383 	{ 0xFF, NULL, NULL },
384 };
385 
386 const struct dcmi_cmd nm_stats_mode[] = {
387 	{ 0x01, "power", "global power" },
388 	{ 0x02, "temps", "inlet temperature" },
389 	{ 0x11, "policy_power", "per policy power" },
390 	{ 0x12, "policy_temps", "per policy inlet temp" },
391 	{ 0x13, "policy_throt", "per policy throttling stats" },
392 	{ 0x1B, "requests", "unhandled requests" },
393 	{ 0x1C, "response", "response time" },
394 	{ 0x1D, "cpu_throttling", "CPU throttling" },
395 	{ 0x1E, "mem_throttling", "memory throttling" },
396 	{ 0x1F, "comm_fail", "host communication failures" },
397 	{ 0xFF, NULL, NULL },
398 };
399 
400 const struct dcmi_cmd nm_policy_action[] = {
401 	{ 0x00, "get", "nm policy get policy_id <0-7> [domain <platform|CPU|Memory>]" },
402 	{ 0x04, "add", "nm policy add policy_id <0-7> [domain <platform|CPU|Memory>] correction auto|soft|hard power <watts>|inlet <temp> trig_lim <param> stats <seconds> enable|disable" },
403 	{ 0x05, "remove", "nm policy remove policy_id <0-7> [domain <platform|CPU|Memory>]" },
404 	{ 0x06, "limiting", "nm policy limiting [domain <platform|CPU|Memory>]" },
405 	{ 0xFF, NULL, NULL },
406 };
407 const struct dcmi_cmd nm_policy_options[] = {
408 	{ 0x01, "enable", "" },
409 	{ 0x02, "disable", "" },
410 	{ 0x03, "domain", "" },
411 	{ 0x04, "inlet", "inlet air temp full limiting (SCRAM)"},
412 	{ 0x06, "correction", "auto, soft, hard" },
413 	{ 0x08, "power", "power limit in watts" },
414 	{ 0x09, "trig_lim", "time to send alert" },
415 	{ 0x0A, "stats", "moving window averaging time" },
416 	{ 0x0B, "policy_id", "policy number" },
417 	{ 0x0C, "volatile", "save policy in volatiel memory" },
418 	{ 0x0D, "cores_off", "at boot time, disable N cores" },
419 	{ 0xFF, NULL, NULL },
420 };
421 
422 /* if "trigger" command used from nm_policy_options */
423 const struct dcmi_cmd nm_trigger[] = {
424 	{ 0x00, "none", "" },
425 	{ 0x01, "temp", "" },
426 	{ 0x02, "reset", "" },
427 	{ 0x03, "boot", "" },
428 	{ 0xFF, NULL, NULL },
429 };
430 
431 /* if "correction" used from nm_policy_options */
432 const struct dcmi_cmd nm_correction[] = {
433 	{ 0x00, "auto", "" },
434 	{ 0x01, "soft", "" },
435 	{ 0x02, "hard", "" },
436 	{ 0xFF, NULL, NULL },
437 };
438 
439 /* returned codes from get policy */
440 const struct dcmi_cmd nm_correction_vals[] = {
441 	{ 0x00, "no T-state use", "" },
442 	{ 0x01, "no T-state use", "" },
443 	{ 0x02, "use T-states", "" },
444 	{ 0xFF, NULL, NULL },
445 };
446 
447 /* if "exception" used from nm_policy_options */
448 const struct dcmi_cmd nm_exception[] = {
449 	{ 0x00, "none", "" },
450 	{ 0x01, "alert", "" },
451 	{ 0x02, "shutdown", "" },
452 	{ 0xFF, NULL, NULL },
453 };
454 
455 const struct dcmi_cmd nm_reset_mode[] = {
456 	{ 0x00, "global", "" },
457 	{ 0x01, "per_policy", "" },
458 	{ 0x1B, "requests", "" },
459 	{ 0x1C, "response", "" },
460 	{ 0x1D, "throttling", "" },
461 	{ 0x1E, "memory", "", },
462 	{ 0x1F, "comm", "" },
463 	{ 0xFF, NULL, NULL },
464 };
465 
466 const struct dcmi_cmd nm_power_range[] = {
467 	{ 0x01, "domain", "domain <platform|CPU|Memory> (default is platform)" },
468 	{ 0x02, "min", " min <integer value>" },
469 	{ 0x03, "max", "max <integer value>" },
470 	{ 0xFF, NULL, NULL },
471 };
472 
473 const struct dcmi_cmd nm_alert_opts[] = {
474 	{ 0x01, "set", "nm alert set chan <chan> dest <dest> string <string>" },
475 	{ 0x02, "get", "nm alert get" },
476 	{ 0x03, "clear", "nm alert clear dest <dest>" },
477 };
478 
479 const struct dcmi_cmd nm_set_alert_param[] = {
480 	{ 0x01, "chan", "chan <channel>" },
481 	{ 0x02, "dest", "dest <destination>" },
482 	{ 0x03, "string", "string <string>" },
483 };
484 
485 const struct dcmi_cmd nm_thresh_cmds[] = {
486 	{ 0x01, "set", "nm thresh set [domain <platform|CPU|Memory>] policy_id <policy> thresh_array" },
487 	{ 0x02, "get", "nm thresh get [domain <platform|CPU|Memory>] policy_id <policy>" },
488 };
489 
490 const struct dcmi_cmd nm_thresh_param[] = {
491 	{ 0x01, "domain", "<platform|CPU|Memory> (default is platform)" },
492 	{ 0x02, "policy_id", "<0-7>" },
493 	{ 0xFF, NULL, NULL },
494 };
495 
496 const struct dcmi_cmd nm_suspend_cmds[] = {
497 	{ 0x01, "set", "nm suspend set [domain <platform|CPU|Memory]> policy_id <policy> <start> <stop> <pattern>" },
498 	{ 0x02, "get", "nm suspend get [domain <platform|CPU|Memory]> policy_id <policy>" },
499 };
500 
501 const struct valstr nm_ccode_vals[] = {
502 	{ 0x80, "Policy ID Invalid"},
503 	{ 0x81, "Domain ID Invalid"},
504 	{ 0x82, "Unknown policy trigger type"},
505 	{ 0x84, "Power Limit out of range"},
506 	{ 0x85, "Correction Time out of range"},
507 	{ 0x86, "Policy Trigger value out of range"},
508 	{ 0x88, "Invalid Mode"},
509 	{ 0x89, "Statistics Reporting Period out of range"},
510 	{ 0x8B, "Invalid value for Aggressive CPU correction field"},
511 	{ 0xA1, "No policy is currently limiting for the specified domain ID"},
512 	{ 0xC4, "No space available"},
513 	{ 0xD4, "Insufficient privledge level due wrong responder LUN"},
514 	{ 0xD5, "Policy exists and param unchangeable while enabled"},
515 	{ 0xD6, "Command subfunction disabled or unavailable"},
516 	{ 0xFF, NULL },
517 };
518 
519 
520 /* End strings */
521 
522 /* This was taken from print_valstr() from helper.c.  It serves the same
523  * purpose but with out the extra formatting.  This function simply prints
524  * the dcmi_cmd struct provided.  verthorz specifies to print vertically or
525  * horizontally.  If the string is printed horizontally then a | will be
526  * printed between each instance of vs[i].str until it is NULL
527  *
528  * @vs:         value string list to print
529  * @title:      name of this value string list
530  * @loglevel:   what log level to print, -1 for stdout
531  * @verthorz:   printed vertically or horizontally, 0 or 1
532  */
533 void
print_strs(const struct dcmi_cmd * vs,const char * title,int loglevel,int verthorz)534 print_strs(const struct dcmi_cmd * vs, const char * title, int loglevel,
535 		int verthorz)
536 {
537 	int i;
538 
539 	if (vs == NULL)
540 		return;
541 
542 	if (title != NULL) {
543 		if (loglevel < 0)
544 			printf("\n%s\n", title);
545 		else
546 			lprintf(loglevel, "\n%s", title);
547 	}
548 	for (i = 0; vs[i].str != NULL; i++) {
549 		if (loglevel < 0) {
550 			if (vs[i].val < 256)
551 				if (verthorz == 0)
552 					printf("    %s    %s\n", vs[i].str, vs[i].desc);
553 				else
554 					printf("%s", vs[i].str);
555 			else if (verthorz == 0)
556 				printf("    %s    %s\n", vs[i].str, vs[i].desc);
557 			else
558 				printf("%s", vs[i].str);
559 		} else {
560 			if (vs[i].val < 256)
561 				lprintf(loglevel, "    %s    %s", vs[i].str, vs[i].desc);
562 			else
563 				lprintf(loglevel, "    %s    %s", vs[i].str, vs[i].desc);
564 		}
565 		/* Check to see if this is NOT the last element in vs.str if true
566 		 * print the | else don't print anything.
567 		 */
568 		if ((verthorz == 1) && (vs[i+1].str != NULL))
569 			printf(" | ");
570 	}
571 	if (verthorz == 0) {
572 		if (loglevel < 0) {
573 			printf("\n");
574 		} else {
575 			lprintf(loglevel, "");
576 		}
577 	}
578 }
579 
580 /* This was taken from str2val() from helper.c.  It serves the same
581  * purpose but with the addition of a desc field from the structure.
582  * This function converts the str from the dcmi_cmd struct provided to the
583  * value associated to the compared string in the struct.
584  *
585  * @str:        string to compare against
586  * @vs:         dcmi_cmd structure
587  */
588 uint16_t
str2val2(const char * str,const struct dcmi_cmd * vs)589 str2val2(const char *str, const struct dcmi_cmd *vs)
590 {
591 	int i;
592 	if (vs == NULL || str == NULL) {
593 		return 0;
594 	}
595 	for (i = 0; vs[i].str != NULL; i++) {
596 		if (strncasecmp(vs[i].str, str,
597 					__maxlen(str, vs[i].str)) == 0) {
598 			return vs[i].val;
599 		}
600 	}
601 	return vs[i].val;
602 }
603 
604 /* This was taken from val2str() from helper.c.  It serves the same
605  * purpose but with the addition of a desc field from the structure.
606  * This function converts the val and returns a string from the dcmi_cmd
607  * struct provided in the struct.
608  *
609  * @val:        value to compare against
610  * @vs:         dcmi_cmd structure
611  */
612 const char *
val2str2(uint16_t val,const struct dcmi_cmd * vs)613 val2str2(uint16_t val, const struct dcmi_cmd *vs)
614 {
615 	static char un_str[32];
616 	int i;
617 
618 	if (vs == NULL)
619 		return NULL;
620 
621 	for (i = 0; vs[i].str != NULL; i++) {
622 		if (vs[i].val == val)
623 			return vs[i].str;
624 	}
625 	memset(un_str, 0, sizeof (un_str));
626 	snprintf(un_str, 32, "Unknown (0x%x)", val);
627 	return un_str;
628 }
629 
630 /* check the DCMI response   from the BMC
631  * @rsp:       Response data structure
632  */
633 static int
chk_rsp(struct ipmi_rs * rsp)634 chk_rsp(struct ipmi_rs * rsp)
635 {
636 	/* if the response from the intf is NULL then the BMC is experiencing
637 	 * some issue and cannot complete the command
638 	 */
639 	if (rsp == NULL) {
640 		lprintf(LOG_ERR, "\n    Unable to get DCMI information");
641 		return 1;
642 	}
643 	/* if the completion code is greater than zero there was an error.  We'll
644 	 * use val2str from helper.c to print the error from either the DCMI
645 	 * completion code struct or the generic IPMI completion_code_vals struct
646 	 */
647 	if ((rsp->ccode >= 0x80) && (rsp->ccode <= 0x8F)) {
648 		lprintf(LOG_ERR, "\n    DCMI request failed because: %s (%x)",
649 				val2str(rsp->ccode, dcmi_ccode_vals), rsp->ccode);
650 		return 1;
651 	} else if (rsp->ccode > 0) {
652 		lprintf(LOG_ERR, "\n    DCMI request failed because: %s (%x)",
653 				val2str(rsp->ccode, completion_code_vals), rsp->ccode);
654 		return 1;
655 	}
656 	/* check to make sure this is a DCMI firmware */
657 	if(rsp->data[0] != IPMI_DCMI) {
658 		printf("\n    A valid DCMI command was not returned! (%x)", rsp->data[0]);
659 		return 1;
660 	}
661 	return 0;
662 }
663 
664 /* check the Node Manager response from the BMC
665  * @rsp:       Response data structure
666  */
667 static int
chk_nm_rsp(struct ipmi_rs * rsp)668 chk_nm_rsp(struct ipmi_rs * rsp)
669 {
670 	/* if the response from the intf is NULL then the BMC is experiencing
671 	 * some issue and cannot complete the command
672 	 */
673 	if (rsp == NULL) {
674 		lprintf(LOG_ERR, "\n    No reponse to NM request");
675 		return 1;
676 	}
677 	/* if the completion code is greater than zero there was an error.  We'll
678 	 * use val2str from helper.c to print the error from either the DCMI
679 	 * completion code struct or the generic IPMI completion_code_vals struct
680 	 */
681 	if ((rsp->ccode >= 0x80) && (rsp->ccode <= 0xD6)) {
682 		lprintf(LOG_ERR, "\n    NM request failed because: %s (%x)",
683 		val2str(rsp->ccode, nm_ccode_vals), rsp->ccode);
684 		return 1;
685 	} else if (rsp->ccode > 0) {
686 		lprintf(LOG_ERR, "\n    NM request failed because: %s (%x)",
687 			val2str(rsp->ccode, completion_code_vals), rsp->ccode);
688 		return 1;
689 	}
690 	/* check to make sure this is a DCMI firmware */
691 	if(rsp->data[0] != 0x57) {
692 		printf("\n    A valid NM command was not returned! (%x)", rsp->data[0]);
693 		return 1;
694 	}
695 	return 0;
696 }
697 
698 /* Get capabilities ipmi response
699  *
700  * This function returns the available capabilities of the platform.
701  * The reason it returns in the rsp struct is so that it can be used for other
702  * purposes.
703  *
704  * returns ipmi response structure
705  *
706  * @intf:   ipmi interface handler
707  * @selector: Parameter selector
708  */
709 struct ipmi_rs *
ipmi_dcmi_getcapabilities(struct ipmi_intf * intf,uint8_t selector)710 ipmi_dcmi_getcapabilities(struct ipmi_intf * intf, uint8_t selector)
711 {
712 	struct ipmi_rq req; /* request data to send to the BMC */
713 	uint8_t msg_data[2]; /* 'raw' data to be sent to the BMC */
714 
715 	msg_data[0] = IPMI_DCMI; /* Group Extension Identification */
716 	msg_data[1] = selector;
717 
718 	memset(&req, 0, sizeof(req));
719 	req.msg.netfn = IPMI_NETFN_DCGRP; /* 0x2C per 1.0 spec */
720 	req.msg.cmd = IPMI_DCMI_COMPAT; /* 0x01 per 1.0 spec */
721 	req.msg.data = msg_data; /* 0xDC 0x01 or the msg_data above */
722 	req.msg.data_len = 2; /* How many times does req.msg.data need to read */
723 
724 	return intf->sendrecv(intf, &req);
725 }
726 /* end capabilities struct */
727 
728 /* Displays capabilities from structure
729  * returns void
730  *
731  * @cmd:        dcmi_cmd structure
732  * @data_val:  holds value of what to display
733  */
734 void
display_capabilities_attributes(const struct dcmi_cmd * cmd,uint8_t data_val)735 display_capabilities_attributes(const struct dcmi_cmd *cmd, uint8_t data_val)
736 {
737 	uint8_t i;
738 	for (i = 0x01; cmd[i-1].val != 0xFF; i++) {
739 		if (data_val & (1<<(i-1))) {
740 			printf("        %s\n", val2str2(i, cmd));
741 		}
742 	}
743 }
744 
745 static int
ipmi_dcmi_prnt_oobDiscover(struct ipmi_intf * intf)746 ipmi_dcmi_prnt_oobDiscover(struct ipmi_intf * intf)
747 {
748 # ifndef IPMI_INTF_LANPLUS
749 	lprintf(LOG_ERR,
750 			"DCMI Discovery is available only when LANplus(IPMI v2.0) is enabled.");
751 	return (-1);
752 # else
753 	struct ipmi_session_params *p;
754 
755 	if (intf->opened == 0 && intf->open != NULL) {
756 		if (intf->open(intf) < 0)
757 			return (-1);
758 	}
759 	if (intf == NULL || intf->session == NULL)
760 		return -1;
761 
762 	p = &intf->ssn_params;
763 
764 	if (p->port == 0)
765 		p->port = IPMI_LAN_PORT;
766 	if (p->privlvl == 0)
767 		p->privlvl = IPMI_SESSION_PRIV_ADMIN;
768 	if (p->timeout == 0)
769 		p->timeout = IPMI_LAN_TIMEOUT;
770 	if (p->retry == 0)
771 		p->retry = IPMI_LAN_RETRY;
772 
773 	if (p->hostname == NULL || strlen((const char *)p->hostname) == 0) {
774 		lprintf(LOG_ERR, "No hostname specified!");
775 		return -1;
776 	}
777 
778 	intf->abort = 1;
779 	intf->session->sol_data.sequence_number = 1;
780 
781 	if (ipmi_intf_socket_connect (intf)  == -1) {
782 		lprintf(LOG_ERR, "Could not open socket!");
783 		return -1;
784 	}
785 
786 	if (intf->fd < 0) {
787 		lperror(LOG_ERR, "Connect to %s failed",
788 			p->hostname);
789 		intf->close(intf);
790 		return -1;
791 	}
792 
793 	intf->opened = 1;
794 
795 	/* Lets ping/pong */
796 	return ipmiv2_lan_ping(intf);
797 # endif
798 }
799 
800 /* This is the get DCMI Capabilities function to see what the BMC supports.
801  *
802  * returns 0 with out error -1 with any errors
803  *
804  * @intf:      ipmi interface handler
805  * @selector:  selection parameter
806  */
807 static int
ipmi_dcmi_prnt_getcapabilities(struct ipmi_intf * intf,uint8_t selector)808 ipmi_dcmi_prnt_getcapabilities(struct ipmi_intf * intf, uint8_t selector)
809 {
810 	struct capabilities cape;
811 	struct ipmi_rs * rsp;
812 	uint8_t reply[16];
813 	rsp = ipmi_dcmi_getcapabilities(intf, selector);
814 	int j;
815 
816 	if(chk_rsp(rsp))
817 		return -1;
818 
819 	/* if there were no errors, the command worked! */
820 	memcpy(&cape, rsp->data, sizeof (cape));
821 	memcpy(&reply, rsp->data, sizeof (reply));
822 	/* check to make sure that this is a 1.0/1.1/1.5 command */
823 	if ((cape.conformance != IPMI_DCMI_CONFORM)
824 			&& (cape.conformance != IPMI_DCMI_1_1_CONFORM)
825 			&& (cape.conformance != IPMI_DCMI_1_5_CONFORM)) {
826 		lprintf(LOG_ERR,
827 				"ERROR!  This command is not available on this platform");
828 		return -1;
829 	}
830 	/* check to make sure that this is a rev .01 or .02 */
831 	if (cape.revision != 0x01 && cape.revision != 0x02) {
832 		lprintf(LOG_ERR,
833 				"ERROR!  This command is not compatible with this version");
834 		return -1;
835 	}
836 	/* 0x01 - platform capabilities
837 	 * 0x02 - Manageability Access Capabilities
838 	 * 0x03 - SEL Capability
839 	 * 0x04 - Identification Capability
840 	 * 0x05 - LAN Out-Of-Band Capability
841 	 * 0x06 - Serial Out-Of-Band TMODE Capability
842 	 */
843 	switch (selector) {
844 	case 0x01:
845 		printf("    Supported DCMI capabilities:\n");
846 		/* loop through each of the entries in the first byte from the
847 		 * struct
848 		 */
849 		printf("\n         Mandatory platform capabilties\n");
850 		display_capabilities_attributes(
851 				dcmi_mandatory_platform_capabilities, cape.data_byte1);
852 		/* loop through each of the entries in the second byte from the
853 		 * struct
854 		 */
855 		printf("\n         Optional platform capabilties\n");
856 		display_capabilities_attributes(
857 				dcmi_optional_platform_capabilities, cape.data_byte2);
858 		/* loop through each of the entries in the third byte from the
859 		 * struct
860 		 */
861 		printf("\n         Managebility access capabilties\n");
862 		display_capabilities_attributes(
863 				dcmi_management_access_capabilities, cape.data_byte3);
864 		break;
865 	case 0x02:
866 		printf("\n    Mandatory platform attributes:\n");
867 		/* byte 1 & 2 data */
868 		printf("\n         SEL Attributes: ");
869 		printf("\n               SEL automatic rollover is ");
870 		/* mask the 2nd byte of the data response with 10000000b or 0x80
871 		 * because of the endian-ness the 15th bit is in the second byte
872 		 */
873 		if ((cape.data_byte2 & 0x80))
874 			printf("enabled");
875 		else
876 			printf("not present");
877 		/* since the number of SEL entries is split across the two data
878 		 * bytes we will need to bit shift and append them together again
879 		 */
880 		/* cast cape.data_byte1 as 16 bits */
881 		uint16_t sel_entries = (uint16_t)cape.data_byte1;
882 		/* or sel_entries with byte 2 and shift it 8 places  */
883 		sel_entries |= (uint16_t)cape.data_byte2 << 8;
884 		printf("\n               %d SEL entries\n", sel_entries & 0xFFF);
885 		/* byte 3 data */
886 		printf("\n         Identification Attributes: \n");
887 		display_capabilities_attributes(
888 				dcmi_id_capabilities_vals, cape.data_byte3);
889 		/* byte 4 data */
890 		printf("\n         Temperature Monitoring Attributes: \n");
891 		display_capabilities_attributes(dcmi_temp_monitoring_vals,
892 				cape.data_byte4);
893 		break;
894 	case 0x03:
895 		printf("\n    Optional Platform Attributes: \n");
896 		/* Power Management */
897 		printf("\n         Power Management:\n");
898 		if (cape.data_byte1 == 0x40) {
899 			printf("                Slave address of device: 20h (BMC)\n" );
900 		} else {
901 			printf("                Slave address of device: %xh (8bits)"
902 					"(Satellite/External controller)\n",
903 					cape.data_byte1);
904 		}
905 		/* Controller channel number (4-7) bits */
906 		if ((cape.data_byte2>>4) == 0x00) {
907 			printf("                Channel number is 0h (Primary BMC)\n");
908 		} else {
909 			printf("                Channel number is %xh \n",
910 					(cape.data_byte2>>4));
911 		}
912 		/* Device revision (0-3) */
913 		printf("                    Device revision is %d \n",
914 				cape.data_byte2 &0xf);
915 		break;
916 	case 0x04:
917 		/* LAN */
918 		printf("\n    Manageability Access Attributes: \n");
919 		if (cape.data_byte1 == 0xFF) {
920 			printf("         Primary LAN channel is not available for OOB\n");
921 		} else {
922 			printf("         Primary LAN channel number: %d is available\n",
923 					cape.data_byte1);
924 		}
925 		if (cape.data_byte2 == 0xFF) {
926 			printf("         Secondary LAN channel is not available for OOB\n");
927 		} else {
928 			printf("         Secondary LAN channel number: %d is available\n",
929 					cape.data_byte2);
930 		}
931 		/* serial */
932 		if (cape.data_byte3 == 0xFF) {
933 			printf("         No serial channel is available\n");
934 		} else {
935 			printf("         Serial channel number: %d is available\n",
936 					cape.data_byte3);
937 		}
938 		break;
939 	case 0x05:
940 		/* Node Manager */
941 		printf("\n    Node Manager Get DCMI Capability Info: \n");
942 		printf("         DCMI Specification %d.%d\n", reply[1], reply[2]);
943 		printf("         Rolling average time period options: %d\n", reply[4]);
944 		printf("         Sample time options: ");
945 		for (j = 1; dcmi_sampling_vals[j-1].str != NULL; j++)
946 			printf(" %s ", val2str2(reply[4+j],dcmi_sampling_vals));
947 		printf("\n");
948 		break;
949 	default:
950 		return -1;
951 	}
952 	return 0;
953 	/* return intf->sendrecv(intf, &req); */
954 }
955 
956 /* This is the get asset tag command.  This checks the length of the asset tag
957  * with the first read, then reads n number of bytes thereafter to get the
958  * complete asset tag.
959  *
960  * @intf:   ipmi interface handler
961  * @offset: where to start reading the asset tag
962  * @length: how much to read
963  *
964  * returns ipmi_rs structure
965  */
966 struct ipmi_rs *
ipmi_dcmi_getassettag(struct ipmi_intf * intf,uint8_t offset,uint8_t length)967 ipmi_dcmi_getassettag(struct ipmi_intf * intf, uint8_t offset, uint8_t length)
968 {
969 	struct ipmi_rq req; /* request data to send to the BMC */
970 	uint8_t msg_data[3]; /* 'raw' data to be sent to the BMC */
971 
972 	msg_data[0] = IPMI_DCMI; /* Group Extension Identification */
973 	msg_data[1] = offset; /* offset 0 */
974 	msg_data[2] = length; /* read one byte */
975 
976 	memset(&req, 0, sizeof(req));
977 	req.msg.netfn = IPMI_NETFN_DCGRP; /* 0x2C per 1.1 spec */
978 	req.msg.cmd = IPMI_DCMI_GETASSET; /* 0x01 per 1.1 spec */
979 	req.msg.data = msg_data; /* msg_data above */
980 	req.msg.data_len = 3; /* How many times does req.msg.data need to read */
981 	return intf->sendrecv(intf, &req);
982 }
983 
984 /* This is the get asset tag command.  The function first checks to see if the
985  * platform is capable of getting the asset tag by calling the getcapabilities
986  * function and checking the response.  Then it checks the length of the asset
987  * tag with the first read, then x number of reads thereafter to get the asset
988  * complete asset tag then print it.
989  *
990  * @intf:   ipmi interface handler
991  *
992  * returns 0 if no failure, -1 with a failure
993  */
994 static int
ipmi_dcmi_prnt_getassettag(struct ipmi_intf * intf)995 ipmi_dcmi_prnt_getassettag(struct ipmi_intf * intf)
996 {
997 	struct ipmi_rs * rsp; /* ipmi response */
998 	uint8_t taglength = 0;
999 	uint8_t getlength = 0;
1000 	uint8_t offset = 0;
1001 	uint8_t i;
1002 	/* now let's get the asset tag length */
1003 	rsp = ipmi_dcmi_getassettag(intf, 0, 0);
1004 	if (chk_rsp(rsp)) {
1005 		return -1;
1006 	}
1007 	taglength = rsp->data[1];
1008 	printf("\n Asset tag: ");
1009 	while (taglength) {
1010 		getlength = taglength / DCMI_MAX_BYTE_SIZE ?
1011 			DCMI_MAX_BYTE_SIZE : taglength%DCMI_MAX_BYTE_SIZE;
1012 		rsp = ipmi_dcmi_getassettag(intf, offset, getlength);
1013 		/* macro has no effect here where can generate sig segv
1014 		 * if rsp occurs with null
1015 		 */
1016 		if (rsp != NULL) {
1017 			GOOD_ASSET_TAG_CCODE(rsp->ccode);
1018 		}
1019 		if (chk_rsp(rsp)) {
1020 			return -1;
1021 		}
1022 		for (i=0; i<getlength; i++) {
1023 			printf("%c", rsp->data[i+2]);
1024 		}
1025 		offset += getlength;
1026 		taglength -= getlength;
1027 	}
1028 	printf("\n");
1029 	return 0;
1030 }
1031 
1032 /* This is the set asset tag command.  This checks the length of the asset tag
1033  * with the first read, then reads n number of bytes thereafter to set the
1034  * complete asset tag.
1035  *
1036  * @intf:   ipmi interface handler
1037  * @offset: offset to write
1038  * @length: number of bytes to write (16 bytes maximum)
1039  * @data:   data to write
1040  *
1041  * returns ipmi_rs structure
1042  */
1043 struct ipmi_rs *
ipmi_dcmi_setassettag(struct ipmi_intf * intf,uint8_t offset,uint8_t length,uint8_t * data)1044 ipmi_dcmi_setassettag(struct ipmi_intf * intf, uint8_t offset, uint8_t length,
1045 		uint8_t *data)
1046 {
1047 	struct ipmi_rq req; /* request data to send to the BMC */
1048 	uint8_t msg_data[3+length]; /* 'raw' data to be sent to the BMC */
1049 
1050 	msg_data[0] = IPMI_DCMI; /* Group Extension Identification */
1051 	msg_data[1] = offset; /* offset 0 */
1052 	msg_data[2] = length; /* read one byte */
1053 
1054 	memset(&req, 0, sizeof(req));
1055 	req.msg.netfn = IPMI_NETFN_DCGRP; /* 0x2C per 1.1 spec */
1056 	req.msg.cmd = IPMI_DCMI_SETASSET; /* 0x08 per 1.1 spec */
1057 	req.msg.data = msg_data; /* msg_data above */
1058 	/* How many times does req.msg.data need to read */
1059 	req.msg.data_len = length + 3;
1060 	memcpy(req.msg.data + 3, data, length);
1061 
1062 	return intf->sendrecv(intf, &req);
1063 }
1064 
1065 static int
ipmi_dcmi_prnt_setassettag(struct ipmi_intf * intf,uint8_t * data)1066 ipmi_dcmi_prnt_setassettag(struct ipmi_intf * intf, uint8_t * data)
1067 {
1068 	struct ipmi_rs * rsp; /* ipmi response */
1069 	uint8_t tmpData[DCMI_MAX_BYTE_SIZE];
1070 	int32_t taglength = 0;
1071 	uint8_t getlength = 0;
1072 	uint8_t offset = 0;
1073 	uint8_t i;
1074 
1075 	/* now let's get the asset tag length */
1076 	taglength = strlen((char *)data);
1077 	if (taglength > 64){
1078 		lprintf(LOG_ERR, "\nValue is too long.");
1079 		return -1;
1080 	}
1081 	printf("\n Set Asset Tag: ");
1082 	while (taglength) {
1083 		getlength = taglength / DCMI_MAX_BYTE_SIZE ?
1084 			DCMI_MAX_BYTE_SIZE : taglength%DCMI_MAX_BYTE_SIZE;
1085 		memcpy(tmpData, data + offset, getlength);
1086 		rsp = ipmi_dcmi_setassettag(intf, offset, getlength, tmpData);
1087 		if (chk_rsp(rsp)) {
1088 			return -1;
1089 		}
1090 		for (i=0; i<getlength; i++) {
1091 			printf("%c", tmpData[i]);
1092 		}
1093 		offset += getlength;
1094 		taglength -= getlength;
1095 	}
1096 	printf("\n");
1097 	return 0;
1098 }
1099 
1100 /* Management Controller Identifier String is provided in order to accommodate
1101  * the requirement for the management controllers to identify themselves.
1102  *
1103  * @intf:   ipmi interface handler
1104  * @offset: offset to read
1105  * @length: number of bytes to read (16 bytes maximum)
1106  *
1107  * returns ipmi_rs structure
1108  */
1109 struct ipmi_rs *
ipmi_dcmi_getmngctrlids(struct ipmi_intf * intf,uint8_t offset,uint8_t length)1110 ipmi_dcmi_getmngctrlids(struct ipmi_intf * intf, uint8_t offset, uint8_t length)
1111 {
1112 	struct ipmi_rq req; /* request data to send to the BMC */
1113 	uint8_t msg_data[3]; /* 'raw' data to be sent to the BMC */
1114 
1115 	msg_data[0] = IPMI_DCMI; /* Group Extension Identification */
1116 	msg_data[1] = offset; /* offset 0 */
1117 	msg_data[2] = length; /* read one byte */
1118 
1119 	memset(&req, 0, sizeof(req));
1120 	req.msg.netfn = IPMI_NETFN_DCGRP; /* 0x2C per 1.1 spec */
1121 	req.msg.cmd = IPMI_DCMI_GETMNGCTRLIDS; /* 0x09 per 1.1 spec */
1122 	req.msg.data = msg_data; /* msg_data above */
1123 	/* How many times does req.msg.data need to read */
1124 	req.msg.data_len = 3;
1125 	return intf->sendrecv(intf, &req);
1126 }
1127 
1128 static int
ipmi_dcmi_prnt_getmngctrlids(struct ipmi_intf * intf)1129 ipmi_dcmi_prnt_getmngctrlids(struct ipmi_intf * intf)
1130 {
1131 	struct ipmi_rs * rsp; /* ipmi response */
1132 	uint8_t taglength = 0;
1133 	uint8_t getlength = 0;
1134 	uint8_t offset = 0;
1135 	uint8_t i;
1136 
1137 	/* now let's get the asset tag length */
1138 	rsp = ipmi_dcmi_getmngctrlids(intf, 0, 1);
1139 
1140 	if (chk_rsp(rsp)) {
1141 		return -1;
1142 	}
1143 
1144 	taglength = rsp->data[1];
1145 
1146 	printf("\n Get Management Controller Identifier String: ");
1147 	while (taglength) {
1148 		getlength = taglength / DCMI_MAX_BYTE_SIZE ?
1149 			DCMI_MAX_BYTE_SIZE : taglength%DCMI_MAX_BYTE_SIZE;
1150 		rsp = ipmi_dcmi_getmngctrlids(intf, offset, getlength);
1151 
1152 		if (chk_rsp(rsp)) {
1153 			return -1;
1154 		}
1155 		for (i=0; i<getlength; i++) {
1156 			printf("%c", rsp->data[i+2]);
1157 		}
1158 		offset += getlength;
1159 		taglength -= getlength;
1160 	}
1161 	printf("\n");
1162 	return 0;
1163 }
1164 
1165 /* Management Controller Identifier String is provided in order to accommodate
1166  * the requirement for the management controllers to identify themselves.
1167  *
1168  * @intf:   ipmi interface handler
1169  * @offset: offset to write
1170  * @length: number of bytes to write (16 bytes maximum)
1171  * @data:   data to write
1172  *
1173  * returns ipmi_rs structure
1174  */
1175 struct ipmi_rs *
ipmi_dcmi_setmngctrlids(struct ipmi_intf * intf,uint8_t offset,uint8_t length,uint8_t * data)1176 ipmi_dcmi_setmngctrlids(struct ipmi_intf * intf, uint8_t offset, uint8_t length,
1177 		uint8_t *data)
1178 {
1179 	struct ipmi_rq req; /* request data to send to the BMC */
1180 	uint8_t msg_data[3+length]; /* 'raw' data to be sent to the BMC */
1181 
1182 	msg_data[0] = IPMI_DCMI; /* Group Extension Identification */
1183 	msg_data[1] = offset; /* offset 0 */
1184 	msg_data[2] = length; /* read one byte */
1185 
1186 	memset(&req, 0, sizeof(req));
1187 	req.msg.netfn = IPMI_NETFN_DCGRP; /* 0x2C per 1.1 spec */
1188 	req.msg.cmd = IPMI_DCMI_SETMNGCTRLIDS; /* 0x0A per 1.1 spec */
1189 	req.msg.data = msg_data; /* msg_data above */
1190 	/* How many times does req.msg.data need to read */
1191 	req.msg.data_len = 3 + length;
1192 	memcpy(req.msg.data + 3, data, length);
1193 
1194 	return intf->sendrecv(intf, &req);
1195 }
1196 
1197 /* Set Asset Tag command provides ability for the management console to set the
1198  * asset tag as appropriate. Management controller is not responsible for the
1199  * data format used for the Asset Tag once modified by IPDC.
1200  *
1201  * @intf:   ipmi interface handler
1202  *
1203  * returns 0 if no failure, -1 with a failure
1204  */
1205 static int
ipmi_dcmi_prnt_setmngctrlids(struct ipmi_intf * intf,uint8_t * data)1206 ipmi_dcmi_prnt_setmngctrlids(struct ipmi_intf * intf, uint8_t * data)
1207 {
1208 	struct ipmi_rs * rsp; /* ipmi response */
1209 	uint8_t tmpData[DCMI_MAX_BYTE_SIZE];
1210 	uint8_t taglength = 0;
1211 	uint8_t getlength = 0;
1212 	uint8_t offset = 0;
1213 	uint8_t i;
1214 
1215 	data += '\0';
1216 	taglength = strlen((char *)data) +1;
1217 
1218 	if (taglength > 64) {
1219 		lprintf(LOG_ERR, "\nValue is too long.");
1220 		return -1;
1221 	}
1222 
1223 	printf("\n Set Management Controller Identifier String Command: ");
1224 	while (taglength) {
1225 		getlength = taglength / DCMI_MAX_BYTE_SIZE ?
1226 			DCMI_MAX_BYTE_SIZE : taglength%DCMI_MAX_BYTE_SIZE;
1227 		memcpy(tmpData, data + offset, getlength);
1228 		rsp = ipmi_dcmi_setmngctrlids(intf, offset, getlength, tmpData);
1229 		/* because after call "Set mc id string" RMCP+ will go down
1230 		 * we have no "rsp"
1231 		 */
1232 		if (strncmp(intf->name, "lanplus", 7)) {
1233 			if (chk_rsp(rsp)) {
1234 				return -1;
1235 			}
1236 		}
1237 		for (i=0; i<getlength; i++) {
1238 			printf("%c", tmpData[i]);
1239 		}
1240 		offset += getlength;
1241 		taglength -= getlength;
1242 	}
1243 	printf("\n");
1244 	return 0;
1245 }
1246 
1247 /* Issues a discovery command to see what sensors are available on the target.
1248  * system.
1249  *
1250  * @intf:   ipmi interface handler
1251  * @isnsr:  entity ID
1252  * @offset:   offset (Entity instace start)
1253  *
1254  * returns ipmi_rs structure
1255  */
1256 struct ipmi_rs *
ipmi_dcmi_discvry_snsr(struct ipmi_intf * intf,uint8_t isnsr,uint8_t offset)1257 ipmi_dcmi_discvry_snsr(struct ipmi_intf * intf, uint8_t isnsr, uint8_t offset)
1258 {
1259 	struct ipmi_rq req; /* ipmi request struct */
1260 	uint8_t msg_data[5]; /* number of request data bytes */
1261 
1262 	msg_data[0] = IPMI_DCMI; /* Group Extension Identification */
1263 	msg_data[1] = 0x01; /* Senser Type = Temp (01h) */
1264 	msg_data[2] = isnsr; /* Sensor Number */
1265 	msg_data[3] = 0x00; /* Entity Instance, set to read all instances */
1266 	msg_data[4] = offset; /* Entity instace start */
1267 
1268 	memset(&req, 0, sizeof(req));
1269 	req.msg.netfn = IPMI_NETFN_DCGRP;
1270 	req.msg.cmd = IPMI_DCMI_GETSNSR;
1271 	req.msg.data = msg_data; /* Contents above */
1272 	req.msg.data_len = 5; /* how many times does req.msg.data need to read */
1273 
1274 	return intf->sendrecv(intf, &req);
1275 }
1276 
1277 /* DCMI sensor discovery
1278  * Uses the dcmi_discvry_snsr_vals struct to print its string and
1279  * uses the numeric values to request the sensor sdr record id.
1280  *
1281  * @intf:   ipmi interface handler
1282  * @isnsr:  entity ID
1283  * @ient:   sensor entity id
1284  */
1285 static int
ipmi_dcmi_prnt_discvry_snsr(struct ipmi_intf * intf,uint8_t isnsr)1286 ipmi_dcmi_prnt_discvry_snsr(struct ipmi_intf * intf, uint8_t isnsr)
1287 {
1288 	int i = 0;
1289 	struct ipmi_rs * rsp; /* ipmi response */
1290 	uint8_t records = 0;
1291 	int8_t instances = 0;
1292 	uint8_t offset = 0;
1293 	uint16_t record_id = 0;
1294 	uint8_t id_buff[16]; /* enough for 8 record IDs */
1295 	rsp = ipmi_dcmi_discvry_snsr(intf, isnsr, 0);
1296 	if (chk_rsp(rsp)) {
1297 		return -1;
1298 	}
1299 	instances = rsp->data[1];
1300 	printf("\n%s: %d temperature sensor%s found:\n",
1301 			val2str2(isnsr, dcmi_discvry_snsr_vals),
1302 			instances,
1303 			(instances > 1) ? "s" : "");
1304 	while(instances > 0) {
1305 		ipmi_dcmi_discvry_snsr(intf, isnsr, offset);
1306 		if (chk_rsp(rsp)) {
1307 			return -1;
1308 		}
1309 		records = rsp->data[2];
1310 		/* cache the data since it may be destroyed by subsequent
1311 		 * ipmi_xxx calls
1312 		 */
1313 		memcpy(id_buff, &rsp->data[3], sizeof (id_buff));
1314 		for (i=0; i<records; i++) {
1315 			/* Record ID is in little endian format */
1316 			record_id = (id_buff[2*i + 1] << 8) + id_buff[2*i];
1317 			printf("Record ID 0x%04x: ", record_id);
1318 			ipmi_print_sensor_info(intf, record_id);
1319 		}
1320 		offset += 8;
1321 		instances -= records;
1322 	}
1323 	return 0;
1324 }
1325 /* end sensor discovery */
1326 
1327 /* Power Management get power reading
1328  *
1329  * @intf:   ipmi interface handler
1330  */
1331 static int
ipmi_dcmi_pwr_rd(struct ipmi_intf * intf,uint8_t sample_time)1332 ipmi_dcmi_pwr_rd(struct ipmi_intf * intf, uint8_t sample_time)
1333 {
1334 	struct ipmi_rs * rsp;
1335 	struct ipmi_rq req;
1336 	struct power_reading val;
1337 	struct tm tm_t;
1338 	time_t t;
1339 	uint8_t msg_data[4]; /* number of request data bytes */
1340 	memset(&tm_t, 0, sizeof(tm_t));
1341 	memset(&t, 0, sizeof(t));
1342 
1343 	msg_data[0] = IPMI_DCMI; /* Group Extension Identification */
1344 	if (sample_time) {
1345 		msg_data[1] = 0x02; /* Enhanced Power Statistics */
1346 		msg_data[2] = sample_time;
1347 	} else {
1348 		msg_data[1] = 0x01; /* Mode Power Status */
1349 		msg_data[2] = 0x00; /* reserved */
1350 	}
1351 	msg_data[3] = 0x00; /* reserved */
1352 
1353 	memset(&req, 0, sizeof(req));
1354 	req.msg.netfn = IPMI_NETFN_DCGRP;
1355 	req.msg.cmd = IPMI_DCMI_GETRED; /* Get power reading */
1356 	req.msg.data = msg_data; /* msg_data above */
1357 	req.msg.data_len = 4; /* how many times does req.msg.data need to read */
1358 
1359 	rsp = intf->sendrecv(intf, &req);
1360 
1361 	if (chk_rsp(rsp)) {
1362 		return -1;
1363 	}
1364 	/* rsp->data[0] is equal to response data byte 2 in spec */
1365 	/* printf("Group Extension Identification: %02x\n", rsp->data[0]); */
1366 	memcpy(&val, rsp->data, sizeof (val));
1367 	t = val.time_stamp;
1368 	gmtime_r(&t, &tm_t);
1369 	printf("\n");
1370 	printf("    Instantaneous power reading:              %8d Watts\n",
1371 			val.curr_pwr);
1372 	printf("    Minimum during sampling period:           %8d Watts\n",
1373 			val.min_sample);
1374 	printf("    Maximum during sampling period:           %8d Watts\n",
1375 			val.max_sample);
1376 	printf("    Average power reading over sample period: %8d Watts\n",
1377 			val.avg_pwr);
1378 	printf("    IPMI timestamp:                           %s",
1379 			asctime(&tm_t));
1380 	printf("    Sampling period:                          ");
1381 	if (sample_time)
1382 		printf("%s \n", val2str2(val.sample,dcmi_sampling_vals));
1383 	else
1384 		printf("%08u Seconds.\n", val.sample/1000);
1385 	printf("    Power reading state is:                   ");
1386 	/* mask the rsp->data so that we only care about bit 6 */
1387 	if((val.state & 0x40) == 0x40) {
1388 		printf("activated");
1389 	} else {
1390 		printf("deactivated");
1391 	}
1392 	printf("\n\n");
1393 	return 0;
1394 }
1395 /* end Power Management get reading */
1396 
1397 
1398 /* This is the get thermalpolicy command.
1399  *
1400  * @intf:   ipmi interface handler
1401  */
1402 int
ipmi_dcmi_getthermalpolicy(struct ipmi_intf * intf,uint8_t entityID,uint8_t entityInstance)1403 ipmi_dcmi_getthermalpolicy(struct ipmi_intf * intf, uint8_t entityID,
1404 		uint8_t entityInstance)
1405 {
1406 	struct ipmi_rs * rsp;
1407 	struct ipmi_rq req;
1408 	struct thermal_limit val;
1409 	uint8_t msg_data[3]; /* number of request data bytes */
1410 
1411 	msg_data[0] = IPMI_DCMI; /* Group Extension Identification */
1412 	msg_data[1] = entityID; /* Inlet Temperature DCMI ID*/
1413 	msg_data[2] = entityInstance; /* Entity Instance */
1414 
1415 	memset(&req, 0, sizeof(req));
1416 	req.msg.netfn = IPMI_NETFN_DCGRP;
1417 	req.msg.cmd = IPMI_DCMI_GETTERMALLIMIT; /* Get thermal policy reading */
1418 	req.msg.data = msg_data; /* msg_data above */
1419 	req.msg.data_len = 3; /* how many times does req.msg.data need to read */
1420 
1421 	rsp = intf->sendrecv(intf, &req);
1422 
1423 	if (chk_rsp(rsp)) {
1424 		return -1;
1425 	}
1426 	/* rsp->data[0] is equal to response data byte 2 in spec */
1427 	memcpy(&val, rsp->data, sizeof (val));
1428 	printf("\n");
1429 	printf("    Persistance flag is:                      %s\n",
1430 			((val.exceptionActions & 0x80) ? "set" : "notset"));
1431 	printf("    Exception Actions, taken if the Temperature Limit exceeded:\n");
1432 	printf("        Hard Power Off system and log event:  %s\n",
1433 			((val.exceptionActions & 0x40) ? "active":"inactive"));
1434 	printf("        Log event to SEL only:                %s\n",
1435 			((val.exceptionActions & 0x20) ? "active":"inactive"));
1436 	printf("    Temperature Limit                         %d degrees\n",
1437 			val.tempLimit);
1438 	printf("    Exception Time                            %d seconds\n",
1439 			val.exceptionTime);
1440 	printf("\n\n");
1441 	return 0;
1442 }
1443 
1444 /* This is the set thermalpolicy command.
1445  *
1446  * @intf:   ipmi interface handler
1447  */
1448 int
ipmi_dcmi_setthermalpolicy(struct ipmi_intf * intf,uint8_t entityID,uint8_t entityInst,uint8_t persistanceFlag,uint8_t actionHardPowerOff,uint8_t actionLogToSEL,uint8_t tempLimit,uint8_t samplingTimeLSB,uint8_t samplingTimeMSB)1449 ipmi_dcmi_setthermalpolicy(struct ipmi_intf * intf,
1450 		uint8_t entityID,
1451 		uint8_t entityInst,
1452 		uint8_t persistanceFlag,
1453 		uint8_t actionHardPowerOff,
1454 		uint8_t actionLogToSEL,
1455 		uint8_t tempLimit,
1456 		uint8_t samplingTimeLSB,
1457 		uint8_t samplingTimeMSB)
1458 {
1459 	struct ipmi_rs * rsp;
1460 	struct ipmi_rq req;
1461 	uint8_t msg_data[7]; /* number of request data bytes */
1462 
1463 	msg_data[0] = IPMI_DCMI; /* Group Extension Identification */
1464 	msg_data[1] = entityID; /* Inlet Temperature DCMI ID*/
1465 	msg_data[2] = entityInst; /* Entity Instance */
1466 	/* persistance and actions or disabled if no actions */
1467 	msg_data[3] = (((persistanceFlag ? 1 : 0) << 7) |
1468 			((actionHardPowerOff? 1 : 0) << 6) |
1469 			((actionLogToSEL ? 1 : 0) << 5));
1470 	msg_data[4] = tempLimit;
1471 	msg_data[5] = samplingTimeLSB;
1472 	msg_data[6] = samplingTimeMSB;
1473 
1474 	memset(&req, 0, sizeof(req));
1475 	req.msg.netfn = IPMI_NETFN_DCGRP;
1476 	/* Get thermal policy reading */
1477 	req.msg.cmd = IPMI_DCMI_SETTERMALLIMIT;
1478 	req.msg.data = msg_data; /* msg_data above */
1479 	/* how many times does req.msg.data need to read */
1480 	req.msg.data_len = 7;
1481 
1482 	rsp = intf->sendrecv(intf, &req);
1483 	if (chk_rsp(rsp)) {
1484 		return -1;
1485 	}
1486 	/* rsp->data[0] is equal to response data byte 2 in spec */
1487 	printf("\nThermal policy %d for %0Xh entity successfully set.\n\n",
1488 			entityInst, entityID);
1489 	return 0;
1490 }
1491 
1492 /* This is Get Temperature Readings Command
1493  *
1494  * returns ipmi response structure
1495  *
1496  * @intf:   ipmi interface handler
1497  */
1498 struct ipmi_rs *
ipmi_dcmi_get_temp_readings(struct ipmi_intf * intf,uint8_t entityID,uint8_t entityInst,uint8_t entityInstStart)1499 ipmi_dcmi_get_temp_readings(struct ipmi_intf * intf,
1500 		uint8_t entityID,
1501 		uint8_t entityInst,
1502 		uint8_t entityInstStart)
1503 {
1504 	struct ipmi_rq req;
1505 	uint8_t msg_data[5]; /* number of request data bytes */
1506 
1507 	msg_data[0] = IPMI_DCMI; /* Group Extension Identification */
1508 	msg_data[1] = 0x01; /* Sensor type */
1509 	msg_data[2] = entityID; /* Entity Instance */
1510 	msg_data[3] = entityInst;
1511 	msg_data[4] = entityInstStart;
1512 
1513 	memset(&req, 0, sizeof(req));
1514 	req.msg.netfn = IPMI_NETFN_DCGRP;
1515 	req.msg.cmd = IPMI_DCMI_GETTEMPRED; /* Get thermal policy reading */
1516 	req.msg.data = msg_data; /* msg_data above */
1517 	/* how many times does req.msg.data need to read */
1518 	req.msg.data_len = 5;
1519 	return intf->sendrecv(intf, &req);
1520 }
1521 
1522 static int
ipmi_dcmi_prnt_get_temp_readings(struct ipmi_intf * intf)1523 ipmi_dcmi_prnt_get_temp_readings(struct ipmi_intf * intf)
1524 {
1525 	struct ipmi_rs * rsp;
1526 	int i,j, tota_inst, get_inst, offset = 0;
1527 	/* Print sensor description */
1528 	printf("\n\tEntity ID\t\t\tEntity Instance\t   Temp. Readings");
1529 	for (i = 0; dcmi_temp_read_vals[i].str != NULL; i++) {
1530 		/* get all of the information about this sensor */
1531 		rsp = ipmi_dcmi_get_temp_readings(intf,
1532 				dcmi_temp_read_vals[i].val, 0, 0);
1533 		if (chk_rsp(rsp)) {
1534 			continue;
1535 		}
1536 		/* Total number of available instances for the Entity ID */
1537 		offset = 0;
1538 		tota_inst = rsp->data[1];
1539 		while (tota_inst > 0) {
1540 			get_inst = ((tota_inst / DCMI_MAX_BYTE_TEMP_READ_SIZE) ?
1541 					DCMI_MAX_BYTE_TEMP_READ_SIZE :
1542 					(tota_inst % DCMI_MAX_BYTE_TEMP_READ_SIZE));
1543 			rsp = ipmi_dcmi_get_temp_readings(intf,
1544 					dcmi_temp_read_vals[i].val, offset, 0);
1545 			if (chk_rsp(rsp)) {
1546 				continue;
1547 			}
1548 			/* Number of sets of Temperature Data in this
1549 			 * response (Max 8 per response)
1550 			 */
1551 			for (j=0; j < rsp->data[2]*2; j=j+2) {
1552 				/* Print Instance temperature info */
1553 				printf("\n%s",dcmi_temp_read_vals[i].desc);
1554 				printf("\t\t%i\t\t%c%i C", rsp->data[j+4],
1555 						((rsp->data[j+3]) >> 7) ?
1556 						'-' : '+', (rsp->data[j+3] & 127));
1557 			}
1558 			offset += get_inst;
1559 			tota_inst -= get_inst;
1560 		}
1561 	}
1562 	return 0;
1563 }
1564 
1565 /* This is Get DCMI Config Parameters Command
1566  *
1567  * returns ipmi response structure
1568  *
1569  * @intf:   ipmi interface handler
1570  */
1571 struct ipmi_rs *
ipmi_dcmi_getconfparam(struct ipmi_intf * intf,int param_selector)1572 ipmi_dcmi_getconfparam(struct ipmi_intf * intf, int param_selector)
1573 {
1574 	struct ipmi_rq req;
1575 	uint8_t msg_data[3]; /* number of request data bytes */
1576 
1577 	msg_data[0] = IPMI_DCMI; /* Group Extension Identification */
1578 	msg_data[1] = param_selector; /* Parameter selector */
1579 	/* Set Selector. Selects a given set of parameters under a given Parameter
1580 	 * selector value. 00h if parameter doesn't use a Set Selector.
1581 	 */
1582 	msg_data[2] = 0x00;
1583 
1584 	memset(&req, 0, sizeof(req));
1585 	req.msg.netfn = IPMI_NETFN_DCGRP;
1586 	req.msg.cmd = IPMI_DCMI_GETCONFPARAM; /* Get DCMI Config Parameters */
1587 	req.msg.data = msg_data; /* Contents above */
1588 	/* how many times does req.msg.data need to read */
1589 	req.msg.data_len = 3;
1590 	return intf->sendrecv(intf, &req);
1591 }
1592 
1593 static int
ipmi_dcmi_prnt_getconfparam(struct ipmi_intf * intf)1594 ipmi_dcmi_prnt_getconfparam(struct ipmi_intf * intf)
1595 {
1596 	struct ipmi_rs * rsp;
1597 	const int dcmi_conf_params = 5;
1598 	int param_selector;
1599 	uint16_t tmp_value = 0;
1600 	/* We are not interested in parameter 1 which always will return 0 */
1601 	for (param_selector = 2 ; param_selector <= dcmi_conf_params;
1602 			param_selector++) {
1603 		rsp = ipmi_dcmi_getconfparam(intf, param_selector);
1604 		if (chk_rsp(rsp)) {
1605 			return -1;
1606 		}
1607 		/* Time to print what we have got */
1608 		switch(param_selector) {
1609 		case 2:
1610 			tmp_value = (rsp->data[4])& 1;
1611 			printf("\n\tDHCP Discovery method\t: ");
1612 			printf("\n\t\tManagement Controller ID String is %s",
1613 					tmp_value ? "enabled" : "disabled");
1614 			printf("\n\t\tVendor class identifier DCMI IANA and Vendor class-specific Informationa are %s",
1615 					((rsp->data[4])& 2) ? "enabled" : "disabled" );
1616 			break;
1617 		case 3:
1618 			printf("\n\tInitial timeout interval\t: %i seconds",
1619 					rsp->data[4]);
1620 			break;
1621 		case 4:
1622 			printf("\n\tServer contact timeout interval\t: %i seconds",
1623 					rsp->data[4] + (rsp->data[5]<<8));
1624 			break;
1625 		case 5:
1626 			printf("\n\tServer contact retry interval\t: %i seconds",
1627 					rsp->data[4] + (rsp->data[5] << 8));
1628 			break;
1629 		default:
1630 			printf("\n\tConfiguration Parameter not supported.");
1631 		}
1632 	}
1633 	return 0;
1634 }
1635 
1636 /* This is Set DCMI Config Parameters Command
1637  *
1638  * returns ipmi response structure
1639  *
1640  * @intf:   ipmi interface handler
1641  */
1642 struct ipmi_rs *
ipmi_dcmi_setconfparam(struct ipmi_intf * intf,uint8_t param_selector,uint16_t value)1643 ipmi_dcmi_setconfparam(struct ipmi_intf * intf, uint8_t param_selector,
1644 		uint16_t value)
1645 {
1646 	struct ipmi_rq req;
1647 	uint8_t msg_data[5]; /* number of request data bytes */
1648 
1649 	msg_data[0] = IPMI_DCMI; /* Group Extension Identification */
1650 	msg_data[1] = param_selector; /* Parameter selector */
1651 	/* Set Selector (use 00h for parameters that only have one set). */
1652 	msg_data[2] = 0x00;
1653 
1654 	if (param_selector > 3) {
1655 		/* One bite more */
1656 		msg_data[3] = value & 0xFF;
1657 		msg_data[4] = value >> 8;
1658 	} else {
1659 		msg_data[3] = value;
1660 	}
1661 
1662 	memset(&req, 0, sizeof(req));
1663 	req.msg.netfn = IPMI_NETFN_DCGRP;
1664 	req.msg.cmd = IPMI_DCMI_SETCONFPARAM; /* Set DCMI Config Parameters */
1665 	req.msg.data = msg_data; /* Contents above */
1666 	if (param_selector > 3) {
1667 		/* One bite more */
1668 		/* how many times does req.msg.data need to read */
1669 		req.msg.data_len = 5;
1670 	} else {
1671 		/* how many times does req.msg.data need to read */
1672 		req.msg.data_len = 4;
1673 	}
1674 	return intf->sendrecv(intf, &req);
1675 }
1676 
1677 /*  Power Management get limit ipmi response
1678  *
1679  * This function returns the currently set power management settings as an
1680  * ipmi response structure.  The reason it returns in the rsp struct is so
1681  * that it can be used in the set limit [slimit()] function to populate
1682  * un-changed or un-edited values.
1683  *
1684  * returns ipmi response structure
1685  *
1686  * @intf:   ipmi interface handler
1687  */
ipmi_dcmi_pwr_glimit(struct ipmi_intf * intf)1688 struct ipmi_rs * ipmi_dcmi_pwr_glimit(struct ipmi_intf * intf)
1689 {
1690 	struct ipmi_rq req;
1691 	uint8_t msg_data[3]; /* number of request data bytes */
1692 
1693 	msg_data[0] = IPMI_DCMI; /* Group Extension Identification */
1694 	msg_data[1] = 0x00; /* reserved */
1695 	msg_data[2] = 0x00; /* reserved */
1696 
1697 	memset(&req, 0, sizeof(req));
1698 	req.msg.netfn = IPMI_NETFN_DCGRP;
1699 	req.msg.cmd = IPMI_DCMI_GETLMT; /* Get power limit */
1700 	req.msg.data = msg_data; /* Contents above */
1701 	/* how many times does req.msg.data need to read */
1702 	req.msg.data_len = 3;
1703 
1704 	return intf->sendrecv(intf, &req);
1705 }
1706 /* end Power Management get limit response */
1707 
1708 /*  Power Management print the get limit command
1709  *
1710  * This function calls the get limit function that returns an ipmi response.
1711  *
1712  * returns 0 else 1 with error
1713  * @intf:   ipmi interface handler
1714  */
1715 static int
ipmi_dcmi_pwr_prnt_glimit(struct ipmi_intf * intf)1716 ipmi_dcmi_pwr_prnt_glimit(struct ipmi_intf * intf)
1717 {
1718 	struct ipmi_rs * rsp;
1719 	struct power_limit val;
1720 	uint8_t realCc = 0xff;
1721 
1722 	rsp = ipmi_dcmi_pwr_glimit(intf);
1723 	/* rsp can be a null so check response before any operation
1724 	 * on it to avoid sig segv
1725 	 */
1726 	if (rsp != NULL) {
1727 		realCc = rsp->ccode;
1728 		GOOD_PWR_GLIMIT_CCODE(rsp->ccode);
1729 	}
1730 	if (chk_rsp(rsp)) {
1731 		return -1;
1732 	}
1733 	/* rsp->data[0] is equal to response data byte 2 in spec */
1734 	/* printf("Group Extension Identification: %02x\n", rsp->data[0]); */
1735 	memcpy(&val, rsp->data, sizeof (val));
1736 	printf("\n    Current Limit State: %s\n",
1737 			(realCc == 0) ?
1738 			"Power Limit Active" : "No Active Power Limit");
1739 	printf("    Exception actions:   %s\n",
1740 			val2str2(val.action, dcmi_pwrmgmt_get_action_vals));
1741 	printf("    Power Limit:         %i Watts\n", val.limit);
1742 	printf("    Correction time:     %i milliseconds\n", val.correction);
1743 	printf("    Sampling period:     %i seconds\n", val.sample);
1744 	printf("\n");
1745 	return 0;
1746 }
1747 /* end print get limit */
1748 
1749 /*  Power Management set limit
1750  *
1751  * Undocumented bounds:
1752  * Power limit: 0 - 0xFFFF
1753  * Correction period 5750ms to 28751ms or 0x1676 to 0x704F
1754  * sample period: 3 sec to 65 sec and 69+
1755  *
1756  * @intf:    ipmi interface handler
1757  * @option:  Power option to change
1758  * @value:   Value of the desired change
1759  */
1760 static int
ipmi_dcmi_pwr_slimit(struct ipmi_intf * intf,const char * option,const char * value)1761 ipmi_dcmi_pwr_slimit(struct ipmi_intf * intf, const char * option,
1762 		const char * value)
1763 {
1764 	struct ipmi_rs * rsp; /* ipmi response */
1765 	struct ipmi_rq req; /* ipmi request (to send) */
1766 	struct power_limit val;
1767 	uint8_t msg_data[15]; /* number of request data bytes */
1768 	uint32_t lvalue = 0;
1769 
1770 	rsp = ipmi_dcmi_pwr_glimit(intf); /* get the power limit settings */
1771 # if 0
1772 	{
1773 		unsigned char counter = 0;
1774 		printf("DATA (%d): ", rsp->data_len);
1775 		for(counter = 0; counter < rsp->data_len; counter ++) {
1776 			printf("%02X ", rsp->data[counter]);
1777 		}
1778 		printf("\n");
1779 	}
1780 # endif
1781 	/* rsp can be a null so check response before any operation on it to
1782 	 * avoid sig segv
1783 	 */
1784 	if (rsp != NULL) {
1785 		GOOD_PWR_GLIMIT_CCODE(rsp->ccode);
1786 	}
1787 	if (chk_rsp(rsp)) {
1788 		return -1;
1789 	}
1790 	memcpy(&val, rsp->data, sizeof (val));
1791 	/* same as above; sets the values of the val struct
1792 	 * DCMI group ID *
1793 	 * val.grp_id = rsp->data[0];
1794 	 * exception action *
1795 	 * val.action = rsp->data[3]; *
1796 	 *
1797 	 * power limit in Watts *
1798 	 * store 16 bits of the rsp from the 4th entity *
1799 	 * val.limit = *(uint16_t*)(&rsp->data[4]);
1800 	 * correction period in mS *
1801 	 * store 32 bits of the rsp from the 6th entity *
1802 	 * val.correction = *(uint32_t*)(&rsp->data[6]);
1803 	 * store 16 bits of the rsp from the 12th entity *
1804 	 * sample period in seconds *
1805 	 * val.sample = *(uint16_t*)(&rsp->data[12]);
1806 	 */
1807 	lprintf(LOG_INFO,
1808 			"DCMI IN  Limit=%d Correction=%d Action=%d Sample=%d\n",
1809 			val.limit, val.correction, val.action, val.sample);
1810 	switch (str2val2(option, dcmi_pwrmgmt_set_usage_vals)) {
1811 	case 0x00:
1812 		/* action */
1813 		switch (str2val2(value, dcmi_pwrmgmt_action_vals)) {
1814 		case 0x00:
1815 			/* no_action */
1816 			val.action = 0;
1817 			break;
1818 		case 0x01:
1819 			/* power_off */
1820 			val.action = 1;
1821 			break;
1822 		case 0x02:
1823 			/* OEM reserved action */
1824 			val.action = 0x02;
1825 			break;
1826 		case 0x03:
1827 			/* OEM reserved action */
1828 			val.action = 0x03;
1829 			break;
1830 		case 0x04:
1831 			/* OEM reserved action */
1832 			val.action = 0x04;
1833 			break;
1834 		case 0x05:
1835 			/* OEM reserved action */
1836 			val.action = 0x05;
1837 			break;
1838 		case 0x06:
1839 			/* OEM reserved action */
1840 			val.action = 0x06;
1841 			break;
1842 		case 0x07:
1843 			/* OEM reserved action */
1844 			val.action = 0x07;
1845 			break;
1846 		case 0x08:
1847 			/* OEM reserved action */
1848 			val.action = 0x08;
1849 			break;
1850 		case 0x09:
1851 			/* OEM reserved action */
1852 			val.action = 0x09;
1853 			break;
1854 		case 0x0a:
1855 			/* OEM reserved action */
1856 			val.action = 0x0a;
1857 			break;
1858 		case 0x0b:
1859 			/* OEM reserved action */
1860 			val.action = 0x0b;
1861 			break;
1862 		case 0x0c:
1863 			/* OEM reserved action */
1864 			val.action = 0x0c;
1865 			break;
1866 		case 0x0d:
1867 			/* OEM reserved action */
1868 			val.action = 0x0d;
1869 			break;
1870 		case 0x0e:
1871 			/* OEM reserved action */
1872 			val.action = 0x0e;
1873 			break;
1874 		case 0x0f:
1875 			/* OEM reserved action */
1876 			val.action = 0x0f;
1877 			break;
1878 		case 0x10:
1879 			/* OEM reserved action */
1880 			val.action = 0x10;
1881 			break;
1882 		case 0x11:
1883 			/* sel_logging*/
1884 			val.action = 0x11;
1885 			break;
1886 		case 0xFF:
1887 			/* error - not a string we knew what to do with */
1888 			lprintf(LOG_ERR, "Given %s '%s' is invalid.",
1889 					option, value);
1890 			return -1;
1891 		}
1892 		break;
1893 	case 0x01:
1894 		/* limit */
1895 		if (str2uint(value, &lvalue) != 0) {
1896 			lprintf(LOG_ERR, "Given %s '%s' is invalid.",
1897 					option, value);
1898 			return (-1);
1899 		}
1900 		val.limit = *(uint16_t*)(&lvalue);
1901 		break;
1902 	case 0x02:
1903 		/* correction */
1904 		if (str2uint(value, &lvalue) != 0) {
1905 			lprintf(LOG_ERR, "Given %s '%s' is invalid.",
1906 					option, value);
1907 			return (-1);
1908 		}
1909 		val.correction = *(uint32_t*)(&lvalue);
1910 		break;
1911 	case 0x03:
1912 		/* sample */
1913 		if (str2uint(value, &lvalue) != 0) {
1914 			lprintf(LOG_ERR, "Given %s '%s' is invalid.",
1915 					option, value);
1916 			return (-1);
1917 		}
1918 		val.sample = *(uint16_t*)(&lvalue);
1919 		break;
1920 	case 0xff:
1921 		/* no valid options */
1922 		return -1;
1923 	}
1924 	lprintf(LOG_INFO, "DCMI OUT Limit=%d Correction=%d Action=%d Sample=%d\n", val.limit, val.correction, val.action, val.sample);
1925 
1926 	msg_data[0] = val.grp_id; /* Group Extension Identification */
1927 	msg_data[1] = 0x00; /* reserved */
1928 	msg_data[2] = 0x00; /* reserved */
1929 	msg_data[3] = 0x00; /* reserved */
1930 	msg_data[4] = val.action; /* exception action; 0x00 disables it */
1931 
1932 	/* fill msg_data[5] with the first 16 bits of val.limit */
1933 	*(uint16_t*)(&msg_data[5]) = val.limit;
1934 	/* msg_data[5] = 0xFF;
1935 	 * msg_data[6] = 0xFF;
1936 	 */
1937 	/* fill msg_data[7] with the first 32 bits of val.correction */
1938 	*(uint32_t*)(&msg_data[7]) = val.correction;
1939 	/* msg_data[7] = 0x76;
1940 	 * msg_data[8] = 0x16;
1941 	 * msg_data[9] = 0x00;
1942 	 * msg_data[10] = 0x00;
1943 	 */
1944 	msg_data[11] = 0x00; /* reserved */
1945 	msg_data[12] = 0x00; /* reserved */
1946 	/* fill msg_data[13] with the first 16 bits of val.sample */
1947 	*(uint16_t*)(&msg_data[13]) = val.sample;
1948 	/* msg_data[13] = 0x03; */
1949 	memset(&req, 0, sizeof(req));
1950 	req.msg.netfn = IPMI_NETFN_DCGRP;
1951 	req.msg.cmd = IPMI_DCMI_SETLMT; /* Set power limit */
1952 	req.msg.data = msg_data; /* Contents above */
1953 	/* how many times does req.msg.data need to read */
1954 	req.msg.data_len = 15;
1955 
1956 	rsp = intf->sendrecv(intf, &req);
1957 
1958 	if (chk_rsp(rsp)) {
1959 		return -1;
1960 	}
1961 	return 0;
1962 }
1963 /* end Power Management set limit */
1964 
1965 /*  Power Management activate deactivate
1966  *
1967  * @intf:    ipmi interface handler
1968  * @option:  uint8_t - 0 to deactivate or 1 to activate
1969  */
1970 static int
ipmi_dcmi_pwr_actdeact(struct ipmi_intf * intf,uint8_t option)1971 ipmi_dcmi_pwr_actdeact(struct ipmi_intf * intf, uint8_t option)
1972 {
1973 	struct ipmi_rs * rsp;
1974 	struct ipmi_rq req;
1975 	uint8_t msg_data[4]; /* number of request data bytes */
1976 
1977 	msg_data[0] = IPMI_DCMI; /* Group Extension Identification */
1978 	msg_data[1] = option; /* 0 = Deactivate 1 = Activate */
1979 	msg_data[2] = 0x00; /* reserved */
1980 	msg_data[3] = 0x00; /* reserved */
1981 
1982 	memset(&req, 0, sizeof(req));
1983 	req.msg.netfn = IPMI_NETFN_DCGRP;
1984 	req.msg.cmd = IPMI_DCMI_PWRACT; /* Act-deactivate power limit */
1985 	req.msg.data = msg_data; /* Contents above */
1986 	req.msg.data_len = 4; /* how mant times does req.msg.data need to read */
1987 
1988 	rsp = intf->sendrecv(intf, &req);
1989 	if (chk_rsp(rsp)) {
1990 		return -1;
1991 	}
1992 	printf("\n    Power limit successfully ");
1993 	if (option == 0x00) {
1994 		printf("deactivated");
1995 	} else {
1996 		printf("activated");
1997 	}
1998 	printf("\n");
1999 	return 0;
2000 }
2001 /* end power management activate/deactivate */
2002 
2003 /* Node Manager discover */
2004 static int
_ipmi_nm_discover(struct ipmi_intf * intf,struct nm_discover * disc)2005 _ipmi_nm_discover(struct ipmi_intf * intf, struct nm_discover *disc)
2006 {
2007 	struct ipmi_rq req; /* request data to send to the BMC */
2008 	struct ipmi_rs *rsp;
2009 	uint8_t msg_data[3]; /* 'raw' data to be sent to the BMC */
2010 
2011 	msg_data[0] = 0x57;
2012 	msg_data[1] = 1;
2013 	msg_data[2] = 0;
2014 	memset(&req, 0, sizeof(req));
2015 	req.msg.netfn = IPMI_NETFN_OEM;
2016 	req.msg.cmd = IPMI_NM_GET_VERSION;
2017 	req.msg.data = msg_data;
2018 	req.msg.data_len = 3;
2019 	rsp = intf->sendrecv(intf, &req);
2020 	if (chk_nm_rsp(rsp)) {
2021 		return -1;
2022 	}
2023 	memcpy(disc, rsp->data, sizeof (struct nm_discover));
2024 	return 0;
2025 }
2026 /* Get NM capabilities
2027  *
2028  * This function returns the available capabilities of the platform.
2029  *
2030  * returns success/failure
2031  *
2032  * @intf:   ipmi interface handler
2033  * @caps:   fills in capability struct
2034  */
2035 static int
_ipmi_nm_getcapabilities(struct ipmi_intf * intf,uint8_t domain,uint8_t trigger,struct nm_capability * caps)2036 _ipmi_nm_getcapabilities(struct ipmi_intf * intf, uint8_t domain, uint8_t trigger, struct nm_capability *caps)
2037 {
2038 	struct ipmi_rq req; /* request data to send to the BMC */
2039 	struct ipmi_rs *rsp;
2040 	uint8_t msg_data[5]; /* 'raw' data to be sent to the BMC */
2041 
2042 	msg_data[0] = 0x57;
2043 	msg_data[1] = 1;
2044 	msg_data[2] = 0;
2045 	msg_data[3] = domain;
2046 	msg_data[4] = trigger; /* power control policy or trigger */
2047 	memset(&req, 0, sizeof(req));
2048 	req.msg.netfn = IPMI_NETFN_OEM;
2049 	req.msg.cmd = IPMI_NM_GET_CAP;
2050 	req.msg.data = msg_data;
2051 	req.msg.data_len = 5;
2052 	rsp = intf->sendrecv(intf, &req);
2053 	if (chk_nm_rsp(rsp)) {
2054 		return -1;
2055 	}
2056 	memcpy(caps, rsp->data, sizeof (struct nm_capability));
2057 	return 0;
2058 }
2059 
2060 static int
_ipmi_nm_get_policy(struct ipmi_intf * intf,uint8_t domain,uint8_t policy_id,struct nm_get_policy * policy)2061 _ipmi_nm_get_policy(struct ipmi_intf * intf, uint8_t domain, uint8_t policy_id, struct nm_get_policy *policy)
2062 {
2063 	struct ipmi_rq req; /* request data to send to the BMC */
2064 	struct ipmi_rs *rsp;
2065 	uint8_t msg_data[5]; /* 'raw' data to be sent to the BMC */
2066 
2067 	msg_data[0] = 0x57;
2068 	msg_data[1] = 1;
2069 	msg_data[2] = 0;
2070 	msg_data[3] = domain;
2071 	msg_data[4] = policy_id;
2072 	memset(&req, 0, sizeof(req));
2073 	req.msg.netfn = IPMI_NETFN_OEM;
2074 	req.msg.cmd = IPMI_NM_GET_POLICY;
2075 	req.msg.data = msg_data;
2076 	req.msg.data_len = 5;
2077 	rsp = intf->sendrecv(intf, &req);
2078 	if (chk_nm_rsp(rsp)) {
2079 		return -1;
2080 	}
2081 	memcpy(policy, rsp->data, sizeof (struct nm_get_policy));
2082 	return 0;
2083 }
2084 static int
_ipmi_nm_set_policy(struct ipmi_intf * intf,struct nm_policy * policy)2085 _ipmi_nm_set_policy(struct ipmi_intf * intf, struct nm_policy *policy)
2086 {
2087 	struct ipmi_rq req; /* request data to send to the BMC */
2088 	struct ipmi_rs *rsp;
2089 
2090 	memset(&req, 0, sizeof(req));
2091 	req.msg.netfn = IPMI_NETFN_OEM;
2092 	req.msg.cmd = IPMI_NM_SET_POLICY;
2093 	req.msg.data = (uint8_t *)policy;
2094 	req.msg.data_len = sizeof(struct nm_policy);
2095 	policy->intel_id[0] = 0x57; policy->intel_id[1] =1; policy->intel_id[2] =0;
2096 	rsp = intf->sendrecv(intf, &req);
2097 	if (chk_nm_rsp(rsp)) {
2098 		return -1;
2099 	}
2100 	return 0;
2101 }
2102 
2103 static int
_ipmi_nm_policy_limiting(struct ipmi_intf * intf,uint8_t domain)2104 _ipmi_nm_policy_limiting(struct ipmi_intf * intf, uint8_t domain)
2105 {
2106 	struct ipmi_rq req; /* request data to send to the BMC */
2107 	struct ipmi_rs *rsp;
2108 	uint8_t msg_data[4]; /* 'raw' data to be sent to the BMC */
2109 
2110 	memset(&req, 0, sizeof(req));
2111 	req.msg.netfn = IPMI_NETFN_OEM;
2112 	req.msg.cmd = IPMI_NM_LIMITING;
2113 	msg_data[0] = 0x57;
2114 	msg_data[1] = 1;
2115 	msg_data[2] = 0;
2116 	msg_data[3] = domain;
2117 	req.msg.data = msg_data;
2118 	req.msg.data_len = 4;
2119 	rsp = intf->sendrecv(intf, &req);
2120 	/* check for special case error of no policy is limiting */
2121 	if (rsp && (rsp->ccode == 0xA1))
2122 		return 0x80;
2123 	else if (chk_nm_rsp(rsp))
2124 		return -1;
2125 	return rsp->data[0];
2126 }
2127 
2128 static int
_ipmi_nm_control(struct ipmi_intf * intf,uint8_t scope,uint8_t domain,uint8_t policy_id)2129 _ipmi_nm_control(struct ipmi_intf * intf, uint8_t scope, uint8_t domain, uint8_t policy_id)
2130 {
2131 	struct ipmi_rq req; /* request data to send to the BMC */
2132 	struct ipmi_rs *rsp;
2133 	uint8_t msg_data[6]; /* 'raw' data to be sent to the BMC */
2134 
2135 	msg_data[0] = 0x57;
2136 	msg_data[1] = 1;
2137 	msg_data[2] = 0;
2138 	msg_data[3] = scope;
2139 	msg_data[4] = domain;
2140 	msg_data[5] = policy_id;
2141 	memset(&req, 0, sizeof(req));
2142 	req.msg.netfn = IPMI_NETFN_OEM;
2143 	req.msg.cmd = IPMI_NM_POLICY_CTL;
2144 	req.msg.data = msg_data;
2145 	req.msg.data_len = 6;
2146 	rsp = intf->sendrecv(intf, &req);
2147 	if (chk_nm_rsp(rsp)) {
2148 		return -1;
2149 	}
2150 	return 0;
2151 }
2152 
2153 /* Get NM statistics
2154  *
2155  * This function returns the statistics
2156  *
2157  * returns success/failure
2158  *
2159  * @intf:   ipmi interface handler
2160  * @selector: Parameter selector
2161  */
2162 static int
_ipmi_nm_statistics(struct ipmi_intf * intf,uint8_t mode,uint8_t domain,uint8_t policy_id,struct nm_statistics * caps)2163 _ipmi_nm_statistics(struct ipmi_intf * intf, uint8_t mode, uint8_t domain, uint8_t policy_id, struct nm_statistics *caps)
2164 {
2165 	struct ipmi_rq req; /* request data to send to the BMC */
2166 	struct ipmi_rs *rsp;
2167 	uint8_t msg_data[6]; /* 'raw' data to be sent to the BMC */
2168 
2169 	msg_data[0] = 0x57;
2170 	msg_data[1] = 1;
2171 	msg_data[2] = 0;
2172 	msg_data[3] = mode;
2173 	msg_data[4] = domain;
2174 	msg_data[5] = policy_id;
2175 	memset(&req, 0, sizeof(req));
2176 	req.msg.netfn = IPMI_NETFN_OEM;
2177 	req.msg.cmd = IPMI_NM_GET_STATS;
2178 	req.msg.data = msg_data;
2179 	req.msg.data_len = 6;
2180 	rsp = intf->sendrecv(intf, &req);
2181 	if (chk_nm_rsp(rsp)) {
2182 		return -1;
2183 	}
2184 	memcpy(caps, rsp->data, sizeof (struct nm_statistics));
2185 	return 0;
2186 }
2187 
2188 static int
_ipmi_nm_reset_stats(struct ipmi_intf * intf,uint8_t mode,uint8_t domain,uint8_t policy_id)2189 _ipmi_nm_reset_stats(struct ipmi_intf * intf, uint8_t mode, uint8_t domain, uint8_t policy_id)
2190 {
2191 	struct ipmi_rq req; /* request data to send to the BMC */
2192 	struct ipmi_rs *rsp;
2193 	uint8_t msg_data[6]; /* 'raw' data to be sent to the BMC */
2194 
2195 	msg_data[0] = 0x57;
2196 	msg_data[1] = 1;
2197 	msg_data[2] = 0;
2198 	msg_data[3] = mode;
2199 	msg_data[4] = domain;
2200 	msg_data[5] = policy_id;
2201 	memset(&req, 0, sizeof(req));
2202 	req.msg.netfn = IPMI_NETFN_OEM;
2203 	req.msg.cmd = IPMI_NM_RESET_STATS;
2204 	req.msg.data = msg_data;
2205 	req.msg.data_len = 6;
2206 	rsp = intf->sendrecv(intf, &req);
2207 	if (chk_nm_rsp(rsp)) {
2208 		return -1;
2209 	}
2210 	return 0;
2211 }
2212 
2213 static int
_nm_set_range(struct ipmi_intf * intf,uint8_t domain,uint16_t minimum,uint16_t maximum)2214 _nm_set_range(struct ipmi_intf * intf, uint8_t domain, uint16_t minimum, uint16_t maximum)
2215 {
2216 	struct ipmi_rq req; /* request data to send to the BMC */
2217 	struct ipmi_rs *rsp;
2218 	uint8_t msg_data[8]; /* 'raw' data to be sent to the BMC */
2219 
2220 	msg_data[0] = 0x57;
2221 	msg_data[1] = 1;
2222 	msg_data[2] = 0;
2223 	msg_data[3] = domain;
2224 	msg_data[4] = minimum & 0xFF;
2225 	msg_data[5] = minimum >> 8;
2226 	msg_data[6] = maximum & 0xFF;
2227 	msg_data[7] = maximum >> 8;
2228 	memset(&req, 0, sizeof(req));
2229 	req.msg.netfn = IPMI_NETFN_OEM;
2230 	req.msg.cmd = IPMI_NM_SET_POWER;
2231 	req.msg.data = msg_data;
2232 	req.msg.data_len = 8;
2233 	rsp = intf->sendrecv(intf, &req);
2234 	if (chk_nm_rsp(rsp)) {
2235 		return -1;
2236 	}
2237 	return 0;
2238 }
2239 
2240 static int
_ipmi_nm_get_alert(struct ipmi_intf * intf,struct nm_set_alert * alert)2241 _ipmi_nm_get_alert(struct ipmi_intf * intf, struct nm_set_alert *alert)
2242 {
2243 	struct ipmi_rq req; /* request data to send to the BMC */
2244 	struct ipmi_rs *rsp;
2245 	uint8_t msg_data[3]; /* 'raw' data to be sent to the BMC */
2246 
2247 	msg_data[0] = 0x57;
2248 	msg_data[1] = 1;
2249 	msg_data[2] = 0;
2250 	memset(&req, 0, sizeof(req));
2251 	req.msg.netfn = IPMI_NETFN_OEM;
2252 	req.msg.cmd = IPMI_NM_GET_ALERT_DS;
2253 	req.msg.data = msg_data;
2254 	req.msg.data_len = 3;
2255 	rsp = intf->sendrecv(intf, &req);
2256 	if (chk_nm_rsp(rsp)) {
2257 		return -1;
2258 	}
2259 	memcpy(alert, rsp->data, sizeof (struct nm_set_alert));
2260 	return 0;
2261 }
2262 
2263 static int
_ipmi_nm_set_alert(struct ipmi_intf * intf,struct nm_set_alert * alert)2264 _ipmi_nm_set_alert(struct ipmi_intf * intf, struct nm_set_alert *alert)
2265 {
2266 	struct ipmi_rq req; /* request data to send to the BMC */
2267 	struct ipmi_rs *rsp;
2268 	uint8_t msg_data[6]; /* 'raw' data to be sent to the BMC */
2269 
2270 	msg_data[0] = 0x57;
2271 	msg_data[1] = 1;
2272 	msg_data[2] = 0;
2273 	msg_data[3] = alert->chan;
2274 	msg_data[4] = alert->dest;
2275 	msg_data[5] = alert->string;
2276 	memset(&req, 0, sizeof(req));
2277 	req.msg.netfn = IPMI_NETFN_OEM;
2278 	req.msg.cmd = IPMI_NM_SET_ALERT_DS;
2279 	req.msg.data = msg_data;
2280 	req.msg.data_len = 6;
2281 	rsp = intf->sendrecv(intf, &req);
2282 	if (chk_nm_rsp(rsp)) {
2283 		return -1;
2284 	}
2285 	return 0;
2286 }
2287 
2288 /*
2289  *
2290  * get alert threshold values.
2291  *
2292  * the list pointer is assumed to point to an array of 16 short integers.
2293  * This array is filled in for valid thresholds returned.
2294  */
2295 static int
_ipmi_nm_get_thresh(struct ipmi_intf * intf,uint8_t domain,uint8_t policy_id,uint16_t * list)2296 _ipmi_nm_get_thresh(struct ipmi_intf * intf, uint8_t domain, uint8_t policy_id, uint16_t *list)
2297 {
2298 	struct ipmi_rq req; /* request data to send to the BMC */
2299 	struct ipmi_rs *rsp;
2300 	uint8_t msg_data[5]; /* 'raw' data to be sent to the BMC */
2301 
2302 	msg_data[0] = 0x57;
2303 	msg_data[1] = 1;
2304 	msg_data[2] = 0;
2305 	msg_data[3] = domain;
2306 	msg_data[4] = policy_id;
2307 	memset(&req, 0, sizeof(req));
2308 	req.msg.netfn = IPMI_NETFN_OEM;
2309 	req.msg.cmd = IPMI_NM_GET_ALERT_TH;
2310 	req.msg.data = msg_data;
2311 	req.msg.data_len = 5;
2312 	rsp = intf->sendrecv(intf, &req);
2313 	if (chk_nm_rsp(rsp)) {
2314 		return -1;
2315 	}
2316 	if (rsp->data[3] > 0)
2317 		*list++ = (rsp->data[5] << 8) | rsp->data[4];
2318 	if (rsp->data[3] > 1)
2319 		*list++ = (rsp->data[7] << 8) | rsp->data[6];
2320 	if (rsp->data[3] > 2)
2321 		*list   = (rsp->data[9] << 8) | rsp->data[8];
2322 	return 0;
2323 }
2324 
2325 static int
_ipmi_nm_set_thresh(struct ipmi_intf * intf,struct nm_thresh * thresh)2326 _ipmi_nm_set_thresh(struct ipmi_intf * intf, struct nm_thresh * thresh)
2327 {
2328 	struct ipmi_rq req; /* request data to send to the BMC */
2329 	struct ipmi_rs *rsp;
2330 	uint8_t msg_data[IPMI_NM_SET_THRESH_LEN]; /* 'raw' data to be sent to the BMC */
2331 
2332 	memset(&msg_data, 0, sizeof(msg_data));
2333 	msg_data[0] = 0x57;
2334 	msg_data[1] = 1;
2335 	msg_data[2] = 0;
2336 	msg_data[3] = thresh->domain;
2337 	msg_data[4] = thresh->policy_id;
2338 	msg_data[5] = thresh->count;
2339 	if (thresh->count > 0) {
2340 		msg_data[7] = thresh->thresholds[0] >> 8;
2341 		msg_data[6] = thresh->thresholds[0] & 0xFF;
2342 	}
2343 	if (thresh->count > 1) {
2344 		msg_data[9] = thresh->thresholds[1] >> 8;
2345 		msg_data[8] = thresh->thresholds[1] & 0xFF;
2346 	}
2347 	if (thresh->count > 2) {
2348 		msg_data[11] = thresh->thresholds[2] >> 8;
2349 		msg_data[10] = thresh->thresholds[2] & 0xFF;
2350 	}
2351 	memset(&req, 0, sizeof(req));
2352 	req.msg.netfn = IPMI_NETFN_OEM;
2353 	req.msg.cmd = IPMI_NM_SET_ALERT_TH;
2354 	req.msg.data = msg_data;
2355 	req.msg.data_len = 6 + (thresh->count * 2);
2356 	rsp = intf->sendrecv(intf, &req);
2357 	if (chk_nm_rsp(rsp)) {
2358 		return -1;
2359 	}
2360 	return 0;
2361 }
2362 
2363 /*
2364  *
2365  * get suspend periods
2366  *
2367  */
2368 static int
_ipmi_nm_get_suspend(struct ipmi_intf * intf,uint8_t domain,uint8_t policy_id,int * count,struct nm_period * periods)2369 _ipmi_nm_get_suspend(struct ipmi_intf * intf, uint8_t domain, uint8_t policy_id, int *count, struct nm_period *periods)
2370 {
2371 	struct ipmi_rq req; /* request data to send to the BMC */
2372 	struct ipmi_rs *rsp;
2373 	uint8_t msg_data[5]; /* 'raw' data to be sent to the BMC */
2374 	int i;
2375 
2376 	msg_data[0] = 0x57;
2377 	msg_data[1] = 1;
2378 	msg_data[2] = 0;
2379 	msg_data[3] = domain;
2380 	msg_data[4] = policy_id;
2381 	memset(&req, 0, sizeof(req));
2382 	req.msg.netfn = IPMI_NETFN_OEM;
2383 	req.msg.cmd = IPMI_NM_GET_SUSPEND;
2384 	req.msg.data = msg_data;
2385 	req.msg.data_len = 5;
2386 	rsp = intf->sendrecv(intf, &req);
2387 	if (chk_nm_rsp(rsp)) {
2388 		return -1;
2389 	}
2390 	*count = rsp->data[3];
2391 	for (i = 0; i < rsp->data[3]; i += 3, periods++) {
2392 		periods->start = rsp->data[4+i];
2393 		periods->stop  = rsp->data[5+i];
2394 		periods->repeat = rsp->data[6+i];
2395 	}
2396 	return 0;
2397 }
2398 
2399 static int
_ipmi_nm_set_suspend(struct ipmi_intf * intf,struct nm_suspend * suspend)2400 _ipmi_nm_set_suspend(struct ipmi_intf * intf, struct nm_suspend *suspend)
2401 {
2402 	struct ipmi_rq req; /* request data to send to the BMC */
2403 	struct ipmi_rs *rsp;
2404 	uint8_t msg_data[21]; /* 6 control bytes + 5 suspend periods, 3 bytes per period */
2405 	struct nm_period *periods;
2406 	int i;
2407 
2408 	msg_data[0] = 0x57;
2409 	msg_data[1] = 1;
2410 	msg_data[2] = 0;
2411 	msg_data[3] = suspend->domain;
2412         msg_data[4] = suspend->policy_id;
2413 	msg_data[5] = suspend->count;
2414 	for (i = 0, periods = &suspend->period[0]; i < (suspend->count*3); i += 3, periods++) {
2415 		msg_data[6+i] = periods->start;
2416 		msg_data[7+i] = periods->stop;
2417 		msg_data[8+i] = periods->repeat;
2418 	}
2419 	memset(&req, 0, sizeof(req));
2420 	req.msg.data_len = 6 + (suspend->count*3);
2421 	req.msg.netfn = IPMI_NETFN_OEM;
2422 	req.msg.cmd = IPMI_NM_SET_SUSPEND;
2423 	req.msg.data = msg_data;
2424         rsp = intf->sendrecv(intf, &req);
2425         if (chk_nm_rsp(rsp)) {
2426 		return -1;
2427 	}
2428 	return 0;
2429 }
2430 
2431 static int
ipmi_nm_getcapabilities(struct ipmi_intf * intf,int argc,char ** argv)2432 ipmi_nm_getcapabilities(struct ipmi_intf * intf, int argc, char **argv)
2433 {
2434 	uint8_t option;
2435 	uint8_t domain = 0;  /* default domain of platform */
2436 	uint8_t trigger = 0; /* default power policy (no trigger) */
2437 	struct nm_capability caps;
2438 
2439         while (--argc > 0) {
2440 		argv++;
2441 		if (argv[0] == NULL) break;
2442 		if ((option = str2val2(argv[0], nm_capability_opts)) == 0xFF) {
2443 			print_strs(nm_capability_opts, "Capability commands", LOG_ERR, 0);
2444 			return -1;
2445 		}
2446 		switch (option) {
2447 		case 0x01:   /* get domain scope */
2448 			if ((domain = str2val2(argv[1], nm_domain_vals)) == 0xFF) {
2449 				print_strs(nm_domain_vals, "Domain Scope:", LOG_ERR, 0);
2450 				return -1;
2451 			}
2452 			break;
2453 		case 0x02:  /* Inlet */
2454 			trigger = 1;
2455 			break;
2456 		case 0x03:  /* Missing power reading */
2457 			trigger = 2;
2458 			break;
2459 		case 0x04:  /* Time after host reset */
2460 			trigger = 3;
2461 			break;
2462 		case 0x05:  /* Boot time policy */
2463 			trigger = 4;
2464 			break;
2465 		default:
2466 			break;
2467 		}
2468 		argc--;
2469 		argv++;
2470 	}
2471 	trigger |= 0x10;
2472 	memset(&caps, 0, sizeof(caps));
2473 	if (_ipmi_nm_getcapabilities(intf, domain, trigger, &caps))
2474 		return -1;
2475 	if (csv_output) {
2476 		printf("%d,%u,%u,%u,%u,%u,%u,%s\n",
2477 			caps.max_settings, caps.max_value,caps.min_value,
2478 			caps.min_corr/1000, caps.max_corr/1000,
2479 			caps.min_stats, caps.max_stats,
2480 			val2str2(caps.scope&0xF, nm_domain_vals));
2481 		return 0;
2482 	}
2483 	printf("    power policies:\t\t%d\n", caps.max_settings);
2484 	switch (trigger&0xF) {
2485 	case 0:  /* power */
2486 		printf("    max_power\t\t%7u Watts\n    min_power\t\t%7u Watts\n",
2487 				caps.max_value, caps.min_value);
2488 		break;
2489 	case 1:  /* Inlet */
2490 		printf("    max_temp\t\t%7u C\n    min_temp\t\t%7u C\n",
2491 				caps.max_value, caps.min_value);
2492 		break;
2493 	case 2: /* Missing reading time */
2494 	case 3: /* Time after host reset */
2495 		printf("    max_time\t\t%7u Secs\n    min_time\t\t%7u Secs\n",
2496 				caps.max_value/10, caps.min_value/10);
2497 		break;
2498 	case 4: /* boot time policy does not use these values */
2499 	default:
2500 		break;
2501 	}
2502 	printf("    min_corr\t\t%7u secs\n    max_corr\t\t%7u secs\n",
2503 				caps.min_corr/1000, caps.max_corr/1000);
2504 	printf("    min_stats\t\t%7u secs\n    max_stats\t\t%7u secs\n",
2505 				caps.min_stats, caps.max_stats);
2506 	printf("    domain scope:\t%s\n", val2str2(caps.scope&0xF, nm_domain_vals));
2507 	return 0;
2508 }
2509 
2510 static int
ipmi_nm_get_policy(struct ipmi_intf * intf,int argc,char ** argv)2511 ipmi_nm_get_policy(struct ipmi_intf * intf, int argc, char **argv)
2512 {
2513 	uint8_t option;
2514 	uint8_t domain = 0; /* default domain of platform */
2515 	uint8_t policy_id = -1;
2516 	struct nm_get_policy policy;
2517 
2518 	memset(&policy, 0, sizeof(policy));
2519 
2520 	while (--argc) {
2521 		argv++;
2522 		if (argv[0] == NULL) break;
2523 		if ((option = str2val2(argv[0], nm_policy_options)) == 0xFF) {
2524 			print_strs(nm_policy_options, "Get Policy commands", LOG_ERR, 0);
2525 			return -1;
2526 		}
2527 		switch (option) {
2528 		case 0x03:   /* get domain scope */
2529 			if ((domain = str2val2(argv[1], nm_domain_vals)) == 0xFF) {
2530 				print_strs(nm_domain_vals, "Domain Scope:", LOG_ERR, 0);
2531 				return -1;
2532 			}
2533 			policy.domain |= domain & 0xF;
2534 			break;
2535 		case 0x0B:   /* policy id */
2536 			if (str2uchar(argv[1], &policy_id) < 0) {
2537 				lprintf(LOG_ERR,"    Policy ID must be a positive integer 0-7.\n");
2538 				return -1;
2539 			}
2540 			break;
2541 		default:
2542 			printf("    Unknown command 0x%x, skipping.\n", option);
2543 			break;
2544 		}
2545 		argc--;
2546 		argv++;
2547 	}
2548         if (policy_id == 0xFF) {
2549 		print_strs(nm_stats_opts, "Missing policy_id parameter:", LOG_ERR, 0);
2550                 return -1;
2551         }
2552 	if (_ipmi_nm_get_policy(intf, policy.domain, policy_id, &policy))
2553 		return -1;
2554 	if (csv_output) {
2555 		printf("%s,0x%x,%s,%s,%s,%u,%u,%u,%u,%s\n",
2556 			val2str2(policy.domain&0xF, nm_domain_vals),
2557 			policy.domain,
2558 			(policy.policy_type & 0x10) ? "power" : "nopower ",
2559 			val2str2(policy.policy_type & 0xF, nm_policy_type_vals),
2560 			val2str2(policy.policy_exception, nm_exception),
2561 			policy.policy_limits,
2562 			policy.corr_time,
2563 			policy.trigger_limit,
2564 			policy.stats_period,
2565 			policy.policy_type & 0x80 ? "volatile" : "non-volatile");
2566 		return 0;
2567 	}
2568 	printf("    Power domain:                             %s\n",
2569 		val2str2(policy.domain&0xF, nm_domain_vals));
2570 	printf("    Policy is %s %s%s%s\n",
2571 		policy.domain&0x10 ? "enabled" : "not enabled",
2572 		policy.domain&0x20 ? "per Domain " : "",
2573 		policy.domain&0x40 ? "Globally " : "",
2574 		policy.domain&0x80 ? "via DCMI api " : "");
2575 	printf("    Policy is %sa power control type.\n", (policy.policy_type & 0x10) ? "" : "not ");
2576 	printf("    Policy Trigger Type:                      %s\n",
2577 		val2str2(policy.policy_type & 0xF, nm_policy_type_vals));
2578 	printf("    Correction Aggressiveness:                %s\n",
2579 		val2str2((policy.policy_type>> 5) & 0x3, nm_correction_vals));
2580 	printf("    Policy Exception Actions:                 %s\n",
2581 		val2str2(policy.policy_exception, nm_exception));
2582 	printf("    Power Limit:                              %u Watts\n",
2583 		policy.policy_limits);
2584 	printf("    Correction Time Limit:                    %u milliseconds\n",
2585 		policy.corr_time);
2586 	printf("    Trigger Limit:                            %u units\n",
2587 		policy.trigger_limit);
2588 	printf("    Statistics Reporting Period:              %u seconds\n",
2589 		policy.stats_period);
2590 	printf("    Policy retention:                         %s\n",
2591 		policy.policy_type & 0x80 ? "volatile" : "non-volatile");
2592 	if ( (policy_id == 0) && ((policy.domain & 0xf) == 0x3) )
2593 		printf("    HW Prot Power domain:                     %s\n",
2594 			policy.policy_type & 0x80 ? "Secondary" : "Primary");
2595 	return 0;
2596 }
2597 
2598 static int
ipmi_nm_policy(struct ipmi_intf * intf,int argc,char ** argv)2599 ipmi_nm_policy(struct ipmi_intf * intf, int argc, char **argv)
2600 {
2601 	uint8_t action;
2602 	uint8_t option;
2603 	uint8_t correction;
2604 	uint8_t domain = 0; /* default domain of platform */
2605 	uint8_t policy_id = -1;
2606 	uint16_t power, period, inlet;
2607 	uint16_t cores;
2608 	uint32_t limit;
2609 	struct nm_policy policy;
2610 
2611 	argv++;
2612 	argc--;
2613 	if ((argv[0] == NULL) ||
2614 			((action = str2val2(argv[0], nm_policy_action)) == 0xFF)) {
2615 		print_strs(nm_policy_action, "Policy commands", LOG_ERR, 0);
2616 		return -1;
2617 	}
2618 	if (action == 0) /* get */
2619 		return (ipmi_nm_get_policy(intf, argc, argv));
2620 	memset(&policy, 0, sizeof(policy));
2621 	/*
2622 	 * nm policy add [domain <param>] enable|disable  policy_id <param> correction <opt> power <watts> limit <param> period <param>
2623 	 * nm policy remove [domain <param>]  policy_id <param>
2624 	 * nm policy limiting {domain <param>]
2625 	 */
2626 	while (--argc > 0) {
2627 		argv++;
2628 		if (argv[0] == NULL) break;
2629 		if ((option = str2val2(argv[0], nm_policy_options)) == 0xFF) {
2630 			print_strs(nm_policy_options, "Policy options", LOG_ERR, 0);
2631 			return -1;
2632 		}
2633 		switch (option) {
2634 		case 0x01:   /* policy enable */
2635 			policy.domain |= IPMI_NM_POLICY_ENABLE;
2636 			break;
2637 		case 0x02:   /* policy disable */
2638 			break;   /* value is initialized to zero already */
2639 		case 0x03:   /* get domain scope */
2640 			if ((domain = str2val2(argv[1], nm_domain_vals)) == 0xFF) {
2641 				print_strs(nm_domain_vals, "Domain Scope:", LOG_ERR, 0);
2642 				return -1;
2643 			}
2644 			policy.domain |= domain & 0xF;
2645 			break;
2646 		case 0x04:   /* inlet */
2647 			if (str2ushort(argv[1], &inlet) < 0) {
2648 				printf("Inlet Temp value must be 20-45.\n");
2649 				return -1;
2650 			}
2651 			policy.policy_type |= 1;
2652 			policy.policy_limits = 0;
2653 			policy.trigger_limit = inlet;
2654 			break;
2655 		case 0x06:   /* get correction action */
2656 			if (action == 0x5) break;   /* skip if this is a remove */
2657 			if ((correction = str2val2(argv[1], nm_correction)) == 0xFF) {
2658 				print_strs(nm_correction, "Correction Actions", LOG_ERR, 0);
2659 				return -1;
2660 			}
2661 			policy.policy_type |= (correction << 5);
2662 			break;
2663 		case 0x07:   /* not implemented */
2664 			break;
2665 		case 0x08:   /* power */
2666 			if (str2ushort(argv[1], &power) < 0) {
2667 				printf("Power limit value must be 0-500.\n");
2668 				return -1;
2669 			}
2670 			policy.policy_limits = power;
2671 			break;
2672 		case 0x09:   /* trigger limit */
2673 			if (str2uint(argv[1], &limit) < 0) {
2674 				printf("Trigger Limit value must be positive integer.\n");
2675 				return -1;
2676 			}
2677 			policy.corr_time = limit;
2678 			break;
2679 		case 0x0A:   /* statistics period */
2680 			if (str2ushort(argv[1], &period) < 0) {
2681 				printf("Statistics Reporting Period must be positive integer.\n");
2682 				return -1;
2683 			}
2684 			policy.stats_period = period;
2685 			break;
2686 		case 0x0B:   /* policy ID */
2687 			if (str2uchar(argv[1], &policy_id) < 0) {
2688 				printf("Policy ID must be a positive integer 0-7.\n");
2689 				return -1;
2690 			}
2691 			policy.policy_id = policy_id;
2692 			break;
2693 		case 0x0C:   /* volatile */
2694 			policy.policy_type |= 0x80;
2695 			break;
2696 		case 0x0D:   /* cores_off, number of cores to disable at boot time */
2697 			policy.policy_type |= 4;
2698 			if (str2ushort(argv[1], &cores) < 0) {
2699 				printf("number of cores disabled must be 1-127.\n");
2700 				return -1;
2701 			}
2702 			if ((cores < 1) || (cores > 127)) {
2703 				printf("number of cores disabled must be 1-127.\n");
2704 				return -1;
2705 			}
2706 			policy.policy_type |= 4;
2707 			policy.policy_limits = cores << 1;
2708 			break;
2709 		default:
2710 			break;
2711 		}
2712 		argc--;
2713 		argv++;
2714 	}
2715 	if (action == 0x06) { /* limiting */
2716 		if ((limit = _ipmi_nm_policy_limiting(intf, domain) == -1))
2717 			return -1;
2718 		printf("limit %x\n", limit);
2719 		return 0;
2720 	}
2721 	if (policy_id == 0xFF) {
2722 		print_strs(nm_stats_opts, "Missing policy_id parameter:", LOG_ERR, 0);
2723 		return -1;
2724 	}
2725 	if (action == 0x04)   /* add */
2726 		policy.policy_type |= 0x10;
2727 	if (_ipmi_nm_set_policy(intf, &policy))
2728 		return -1;
2729 	return 0;
2730 }
2731 /* end policy */
2732 
2733 static int
ipmi_nm_control(struct ipmi_intf * intf,int argc,char ** argv)2734 ipmi_nm_control(struct ipmi_intf * intf, int argc, char **argv)
2735 {
2736 	uint8_t action;
2737 	uint8_t scope = 0;   /* default control scope of global */
2738 	uint8_t domain = 0;  /* default domain of platform */
2739 	uint8_t policy_id = -1;
2740 
2741 	argv++;
2742 	argc--;
2743 	/* nm_ctl_cmds returns 0 for disable, 1 for enable */
2744 	if ((argv[0] == NULL) ||
2745 			((action = str2val2(argv[0], nm_ctl_cmds)) == 0xFF)) {
2746 		print_strs(nm_ctl_cmds, "Control parameters:", LOG_ERR, 0);
2747 		print_strs(nm_ctl_domain, "control Scope (required):", LOG_ERR, 0);
2748 		return -1;
2749 	}
2750 	argv++;
2751 	while (--argc) {
2752 		/* nm_ctl_domain returns correct bit field except for action */
2753 		if ((argv[0] == NULL) ||
2754 				((scope = str2val2(argv[0], nm_ctl_domain)) == 0xFF)) {
2755 			print_strs(nm_ctl_domain, "Control Scope (required):", LOG_ERR, 0);
2756 			return -1;
2757 		}
2758 		argv++;
2759 		if (argv[0] == NULL) break;
2760 		if (scope == 0x02) { /* domain */
2761 			if ((domain = str2val2(argv[0], nm_domain_vals)) == 0xFF) {
2762 				print_strs(nm_domain_vals, "Domain Scope:", LOG_ERR, 0);
2763 				return -1;
2764 			}
2765 		} else if (scope == 0x04) { /* per_policy */
2766 
2767 			if (str2uchar(argv[0], &policy_id) < 0) {
2768 				lprintf(LOG_ERR,"Policy ID must be a positive integer.\n");
2769 				return -1;
2770 			}
2771 			break;
2772 		}
2773 		argc--;
2774 		argv++;
2775 	}
2776         if ((scope == 0x04) && (policy_id == 0xFF)) {
2777 		print_strs(nm_stats_opts, "Missing policy_id parameter:", LOG_ERR, 0);
2778 		return -1;
2779 	}
2780 	if (_ipmi_nm_control(intf, scope|(action&1), domain, policy_id) < 0 )
2781 		return -1;
2782 	return 0;
2783 }
2784 
2785 static int
ipmi_nm_get_statistics(struct ipmi_intf * intf,int argc,char ** argv)2786 ipmi_nm_get_statistics(struct ipmi_intf * intf, int argc, char **argv)
2787 {
2788 	uint8_t mode = 0;
2789 	uint8_t option;
2790 	uint8_t domain = 0;   /* default domain of platform */
2791 	uint8_t policy_id = -1;
2792 	int     policy_mode = 0;
2793 	int     cut;
2794 	char   *units = "";
2795 	char    datebuf[27];
2796 	struct nm_statistics stats;
2797 	struct tm tm_t;
2798 	time_t t;
2799 
2800 	argv++;
2801 	if ((argv[0] == NULL) ||
2802 			((mode = str2val2(argv[0], nm_stats_mode)) == 0xFF)) {
2803 		print_strs(nm_stats_mode, "Statistics commands", LOG_ERR, 0);
2804 		return -1;
2805 	}
2806 	while (--argc) {
2807 		argv++;
2808 		if (argv[0] == NULL) break;
2809 		if ((option = str2val2(argv[0], nm_stats_opts)) == 0xFF) {
2810 				print_strs(nm_stats_opts, "Control Scope options", LOG_ERR, 0);
2811 			return -1;
2812 		}
2813 		switch (option) {
2814 		case 0x01:   /* get domain scope */
2815 			if ((domain = str2val2(argv[1], nm_domain_vals)) == 0xFF) {
2816 				print_strs(nm_domain_vals, "Domain Scope:", LOG_ERR, 0);
2817 				return -1;
2818 			}
2819 			break;
2820 		case 0x02:   /* policy ID */
2821 			if (str2uchar(argv[1], &policy_id) < 0) {
2822 				lprintf(LOG_ERR,"Policy ID must be a positive integer.\n");
2823 				return -1;
2824 			}
2825 			break;
2826 		default:
2827 			break;
2828 		}
2829 		argc--;
2830 		argv++;
2831 	}
2832 
2833 	switch (mode) {
2834 	case 0x01:
2835 		units = "Watts";
2836 		break;
2837 	case 0x02:
2838 		units = "Celsius";
2839 		break;
2840 	case 0x03:
2841 		units = "%";
2842 		break;
2843 	case 0x11:
2844 	case 0x12:
2845 	case 0x13:
2846 		policy_mode = 1;
2847 		units = (mode == 0x11) ? "Watts" : (mode == 0x12) ? "Celsius" : " %";
2848 		if (policy_id == 0xFF) {
2849 			print_strs(nm_stats_opts, "Missing policy_id parameter:", LOG_ERR, 0);
2850 			return -1;
2851 		}
2852 		break;
2853 	default:
2854 		break;
2855 	}
2856 	if (_ipmi_nm_statistics(intf, mode, domain, policy_id, &stats))
2857 		return -1;
2858 	t = stats.time_stamp;
2859 	gmtime_r(&t, &tm_t);
2860 	sprintf(datebuf, "%s", asctime(&tm_t));
2861 	cut = strlen(datebuf) -1;
2862 	datebuf[cut] = 0;
2863 	if (csv_output) {
2864 		printf("%s,%s,%s,%s,%s,%d,%d,%d,%d,%s,%d\n",
2865 			val2str2(stats.id_state & 0xF, nm_domain_vals),
2866 			((stats.id_state >> 4) & 1) ? (policy_mode ? "Policy Enabled" : "Globally Enabled") : "Disabled" ,
2867 			((stats.id_state >> 5) & 1) ? "active" : "suspended",
2868 			((stats.id_state >> 6) & 1) ? "in progress" : "suspended",
2869 			((stats.id_state >> 7) & 1) ? "triggered" : "not triggered",
2870 			stats.curr_value,
2871 			stats.min_value,
2872 			stats.max_value,
2873 			stats.ave_value,
2874 			datebuf,
2875 			stats.stat_period);
2876 		return 0;
2877 	}
2878 	printf("    Power domain:                             %s\n",
2879 		val2str2(stats.id_state & 0xF, nm_domain_vals));
2880 	printf("    Policy/Global Admin state                 %s\n",
2881 		((stats.id_state >> 4) & 1) ? (policy_mode ? "Policy Enabled" : "Globally Enabled") : "Disabled" );
2882 	printf("    Policy/Global Operational state           %s\n",
2883 		((stats.id_state >> 5) & 1) ? "active" : "suspended");
2884 	printf("    Policy/Global Measurement state           %s\n",
2885 		((stats.id_state >> 6) & 1) ? "in progress" : "suspended");
2886 	printf("    Policy Activation state                   %s\n",
2887 		((stats.id_state >> 7) & 1) ? "triggered" : "not triggered");
2888 	printf("    Instantaneous reading:                    %8d %s\n",
2889 		stats.curr_value, units);
2890 	printf("    Minimum during sampling period:           %8d %s\n",
2891 		stats.min_value, units);
2892 	printf("    Maximum during sampling period:           %8d %s\n",
2893 		stats.max_value, units);
2894 	printf("    Average reading over sample period:       %8d %s\n",
2895 		stats.ave_value, units);
2896 	printf("    IPMI timestamp:                           %s\n",
2897 		datebuf);
2898 	printf("    Sampling period:                          %08d Seconds.\n", stats.stat_period);
2899 	printf("\n");
2900 	return 0;
2901 }
2902 
2903 static int
ipmi_nm_reset_statistics(struct ipmi_intf * intf,int argc,char ** argv)2904 ipmi_nm_reset_statistics(struct ipmi_intf * intf, int argc, char **argv)
2905 {
2906 	uint8_t mode;
2907 	uint8_t option;
2908 	uint8_t domain = 0;   /* default domain of platform */
2909 	uint8_t policy_id = -1;
2910 
2911 	argv++;
2912 	if ((argv[0] == NULL) ||
2913 			((mode = str2val2(argv[0], nm_reset_mode)) == 0xFF)) {
2914 		print_strs(nm_reset_mode, "Reset Statistics Modes:", LOG_ERR, 0);
2915 		return -1;
2916 	}
2917 	while (--argc) {
2918 		argv++;
2919 		if (argv[0] == NULL) break;
2920 		if ((option = str2val2(argv[0], nm_stats_opts)) == 0xFF) {
2921 			print_strs(nm_stats_opts, "Reset Scope options", LOG_ERR, 0);
2922 			return -1;
2923 		}
2924 		switch (option) {
2925 		case 0x01:   /* get domain scope */
2926 			if ((domain = str2val2(argv[1], nm_domain_vals)) == 0xFF) {
2927 				print_strs(nm_domain_vals, "Domain Scope:", LOG_ERR, 0);
2928 				return -1;
2929 			}
2930 			break;
2931 		case 0x02:   /* policy ID */
2932 			if (str2uchar(argv[1], &policy_id) < 0) {
2933 				lprintf(LOG_ERR,"Policy ID must be a positive integer.\n");
2934 				return -1;
2935 			}
2936 			break;
2937 		default:
2938 			break;
2939 		}
2940 		argc--;
2941 		argv++;
2942 	}
2943 	if (mode && (policy_id == 0xFF)) {
2944 		print_strs(nm_stats_opts, "Missing policy_id parameter:", LOG_ERR, 0);
2945 		return -1;
2946 	}
2947 	if (_ipmi_nm_reset_stats(intf, mode, domain, policy_id) < 0)
2948 		return -1;
2949 	return 0;
2950 }
2951 
2952 static int
ipmi_nm_set_range(struct ipmi_intf * intf,int argc,char ** argv)2953 ipmi_nm_set_range(struct ipmi_intf * intf, int argc, char **argv)
2954 {
2955 	uint8_t domain = 0;
2956 	uint8_t param;
2957 	uint16_t minimum = -1;
2958 	uint16_t maximum = -1;
2959 
2960 	while (--argc) {
2961 		argv++;
2962 		if (argv[0] == NULL) break;
2963 		if ((param = str2val2(argv[0], nm_power_range)) == 0xFF) {
2964 			print_strs(nm_power_range, "power range parameters:", LOG_ERR, 0);
2965 			return -1;
2966 		}
2967 		switch (param) {
2968 		case 0x01:   /* get domain scope */
2969 			if ((domain = str2val2(argv[1], nm_domain_vals)) == 0xFF) {
2970 				print_strs(nm_domain_vals, "Domain Scope:", LOG_ERR, 0);
2971 				return -1;
2972 			}
2973 			break;
2974 		case 0x02: /* min */
2975 			if (str2ushort(argv[1], &minimum) < 0) {
2976 				lprintf(LOG_ERR,"Power minimum must be a positive integer.\n");
2977 				return -1;
2978 			}
2979 			break;
2980 		case 0x03: /* max */
2981 			if (str2ushort(argv[1], &maximum) < 0) {
2982 				lprintf(LOG_ERR,"Power maximum must be a positive integer.\n");
2983 				return -1;
2984 			}
2985 			break;
2986 		default:
2987 			break;
2988 		}
2989 		argc--;
2990 		argv++;
2991 	}
2992 	if ((minimum == 0xFFFF) || (maximum == 0xFFFF)) {
2993 		lprintf(LOG_ERR,"Missing parameters: nm power range min <minimum> max <maximum>.\n");
2994 		return -1;
2995 	}
2996 	if (_nm_set_range(intf, domain, minimum, maximum) < 0)
2997 		return -1;
2998 	return 0;
2999 }
3000 
3001 static int
ipmi_nm_get_alert(struct ipmi_intf * intf)3002 ipmi_nm_get_alert(struct ipmi_intf * intf)
3003 {
3004 	struct nm_set_alert alert;
3005 
3006 	memset(&alert, 0, sizeof(alert));
3007 	if (_ipmi_nm_get_alert(intf, &alert))
3008 		return -1;
3009 	if (csv_output) {
3010 		printf("%d,%s,0x%x,%s,0x%x\n",
3011 				alert.chan&0xF,
3012 				(alert.chan >> 7) ? "not registered" : "registered",
3013 				alert.dest,
3014 				(alert.string >> 7) ? "yes" : "no",
3015 				alert.string & 0x7F);
3016 		return 0;
3017 	}
3018 	printf("    Alert Chan:                                  %d\n",
3019 		alert.chan&0xF);
3020 	printf("    Alert Receiver:                              %s\n",
3021 		(alert.chan >> 7) ? "not registered" : "registered");
3022 	printf("    Alert Lan Destination:                       0x%x\n",
3023 		alert.dest);
3024 	printf("    Use Alert String:                            %s\n",
3025 		(alert.string >> 7) ? "yes" : "no");
3026 	printf("    Alert String Selector:                       0x%x\n",
3027 		alert.string & 0x7F);
3028 	return 0;
3029 }
3030 
3031 static int
ipmi_nm_alert(struct ipmi_intf * intf,int argc,char ** argv)3032 ipmi_nm_alert(struct ipmi_intf * intf, int argc, char **argv)
3033 {
3034 	uint8_t param;
3035 	uint8_t action;
3036 	uint8_t chan = -1;
3037 	uint8_t dest = -1;
3038 	uint8_t string = -1;
3039 	struct nm_set_alert alert;
3040 
3041 	argv++;
3042 	argc--;
3043 	if ((argv[0] == NULL) ||
3044 			((action = str2val2(argv[0], nm_alert_opts)) == 0xFF)) {
3045 		print_strs(nm_alert_opts, "Alert commands", LOG_ERR, 0);
3046 		return -1;
3047 	}
3048 	if (action == 0x02) /* get */
3049 		return (ipmi_nm_get_alert(intf));
3050 	/* set */
3051 	memset(&alert, 0, sizeof(alert));
3052 	while (--argc) {
3053 		argv++;
3054 		if (argv[0] == NULL) break;
3055 		if ((param = str2val2(argv[0], nm_set_alert_param)) == 0xFF) {
3056 			print_strs(nm_set_alert_param, "Set alert Parameters:", LOG_ERR, 0);
3057 			return -1;
3058 		}
3059 		switch (param) {
3060 		case 0x01: /* channnel */
3061 			if (str2uchar(argv[1], &chan) < 0) {
3062 				lprintf(LOG_ERR,"Alert Lan chan must be a positive integer.\n");
3063 				return -1;
3064 			}
3065 			if (action == 0x03)  /* Clear */
3066 				chan |= 0x80;   /* deactivate alert reciever */
3067 			break;
3068 		case 0x02:  /* dest */
3069 			if (str2uchar(argv[1], &dest) < 0) {
3070 				lprintf(LOG_ERR,"Alert Destination must be a positive integer.\n");
3071 				return -1;
3072 			}
3073 			break;
3074 		case 0x03:  /* string number */
3075 			if (str2uchar(argv[1], &string) < 0) {
3076 				lprintf(LOG_ERR,"Alert String # must be a positive integer.\n");
3077 				return -1;
3078 			}
3079 			string |= 0x80;   /* set string select flag */
3080 			break;
3081 		}
3082 		argc--;
3083 		argv++;
3084 	}
3085 	if ((chan == 0xFF) || (dest == 0xFF)) {
3086 		print_strs(nm_set_alert_param, "Must set alert chan and dest params.", LOG_ERR, 0);
3087 		return -1;
3088 	}
3089 	if (string == 0xFF) string = 0;
3090 	alert.chan = chan;
3091 	alert.dest = dest;
3092 	alert.string = string;
3093 	if (_ipmi_nm_set_alert(intf, &alert))
3094 		return -1;
3095 	return 0;
3096 }
3097 
3098 static int
ipmi_nm_get_thresh(struct ipmi_intf * intf,uint8_t domain,uint8_t policy_id)3099 ipmi_nm_get_thresh(struct ipmi_intf *intf, uint8_t domain, uint8_t policy_id)
3100 {
3101 	uint16_t list[3];
3102 
3103 	memset(list, 0, sizeof(list));
3104 	if (_ipmi_nm_get_thresh(intf, domain, policy_id, &list[0]))
3105 		return -1;
3106 
3107 	printf("    Alert Threshold domain:                   %s\n",
3108 			val2str2(domain, nm_domain_vals));
3109 	printf("    Alert Threshold Policy ID:                %d\n",
3110 			policy_id);
3111 	printf("    Alert Threshold 1:                        %d\n",
3112 			list[0]);
3113 	printf("    Alert Threshold 2:                        %d\n",
3114 			list[1]);
3115 	printf("    Alert Threshold 3:                        %d\n",
3116 			list[2]);
3117 	return 0;
3118 }
3119 
3120 static int
ipmi_nm_thresh(struct ipmi_intf * intf,int argc,char ** argv)3121 ipmi_nm_thresh(struct ipmi_intf * intf, int argc, char **argv)
3122 {
3123 	uint8_t option;
3124 	uint8_t action;
3125 	uint8_t domain = 0;   /* default domain of platform */
3126 	uint8_t policy_id = -1;
3127 	struct nm_thresh thresh;
3128 	int i = 0;
3129 
3130 	argv++;
3131 	argc--;
3132 	/* set or get */
3133 	if ((argv[0] == NULL) || (argc < 3) ||
3134 			((action = str2val2(argv[0], nm_thresh_cmds)) == 0xFF)) {
3135 		print_strs(nm_thresh_cmds, "Theshold commands", LOG_ERR, 0);
3136 		return -1;
3137 	}
3138 	memset(&thresh, 0, sizeof(thresh));
3139 	while (--argc) {
3140 		argv++;
3141 		if (argv[0] == NULL) break;
3142 		option = str2val2(argv[0], nm_thresh_param);
3143 		switch (option) {
3144 		case 0x01:   /* get domain scope */
3145 			if ((domain = str2val2(argv[1], nm_domain_vals)) == 0xFF) {
3146 				print_strs(nm_domain_vals, "Domain Scope:", LOG_ERR, 0);
3147 				return -1;
3148 			}
3149 			argc--;
3150 			argv++;
3151 			break;
3152 		case 0x02:   /* policy ID */
3153 			if (str2uchar(argv[1], &policy_id) < 0) {
3154 				lprintf(LOG_ERR,"Policy ID must be a positive integer.\n");
3155 				return -1;
3156 			}
3157 			argc--;
3158 			argv++;
3159 			break;
3160 		case 0xFF:
3161 			if (i > 2) {
3162 				lprintf(LOG_ERR,"Set Threshold requires 1, 2, or 3 threshold integer values.\n");
3163 				return -1;
3164 			}
3165 			if (str2ushort(argv[0], &thresh.thresholds[i++]) < 0) {
3166 				lprintf(LOG_ERR,"threshold value %d count must be a positve integer.\n", i);
3167 				return -1;
3168 			}
3169 		default:
3170 			break;
3171 		}
3172 	}
3173 	if (policy_id == 0xFF) {
3174 		print_strs(nm_stats_opts, "Missing policy_id parameter:", LOG_ERR, 0);
3175 		return -1;
3176 	}
3177 	if (action == 0x02) /* get */
3178 		return (ipmi_nm_get_thresh(intf, domain, policy_id));
3179 	thresh.domain = domain;
3180 	thresh.policy_id = policy_id;
3181 	thresh.count = i;
3182 	if (_ipmi_nm_set_thresh(intf, &thresh) < 0)
3183 		return -1;
3184 	return 0;
3185 }
3186 
3187 static inline int
click2hour(int click)3188 click2hour(int click)
3189 {
3190 	if ((click*6) < 60) return 0;
3191 	return ((click*6)/60);
3192 }
3193 
3194 static inline int
click2min(int click)3195 click2min(int click)
3196 {
3197 	if (!click) return 0;
3198 	if ((click*6) < 60) return click*6;
3199 	return (click*6)%60;
3200 }
3201 
3202 static int
ipmi_nm_get_suspend(struct ipmi_intf * intf,uint8_t domain,uint8_t policy_id)3203 ipmi_nm_get_suspend(struct ipmi_intf *intf, uint8_t domain, uint8_t policy_id)
3204 {
3205 	struct nm_period periods[5];
3206 	int i;
3207 	int j;
3208 	int count = 0;
3209 	const char *days[7] = {"M", "Tu", "W", "Th", "F", "Sa", "Su"};
3210 
3211 	memset(periods, 0, sizeof(periods));
3212 	if (_ipmi_nm_get_suspend(intf, domain, policy_id, &count, &periods[0]))
3213 		return -1;
3214 
3215 	printf("    Suspend Policy domain:                    %s\n",
3216 			val2str2(domain, nm_domain_vals));
3217 	printf("    Suspend Policy Policy ID:                 %d\n",
3218 			policy_id);
3219 	if (!count) {
3220 		printf("    No suspend Periods.\n");
3221 		return 0;
3222 	}
3223 	for (i = 0; i < count; i++) {
3224 		printf("    Suspend Period %d:                         %02d:%02d to %02d:%02d",
3225 			i, click2hour(periods[i].start), click2min(periods[i].start),
3226 			click2hour(periods[i].stop), click2min(periods[i].stop));
3227 		if (periods[i].repeat) printf(", ");
3228 		for (j = 0; j < 7; j++)
3229 			printf("%s",  (periods[i].repeat >> j)&1 ? days[j] : "");
3230 		printf("\n");
3231 	}
3232 	return 0;
3233 }
3234 
3235 static int
ipmi_nm_suspend(struct ipmi_intf * intf,int argc,char ** argv)3236 ipmi_nm_suspend(struct ipmi_intf * intf, int argc, char **argv)
3237 {
3238 	uint8_t option;
3239 	uint8_t action;
3240 	uint8_t domain = 0;   /* default domain of platform */
3241 	uint8_t policy_id = -1;
3242 	uint8_t count = 0;
3243 	struct nm_suspend suspend;
3244 	int i;
3245 
3246 	argv++;
3247 	argc--;
3248 	/* set or get */
3249 	if ((argv[0] == NULL) || (argc < 3) ||
3250 			((action = str2val2(argv[0], nm_suspend_cmds)) == 0xFF)) {
3251 		print_strs(nm_suspend_cmds, "Suspend commands", LOG_ERR, 0);
3252 		return -1;
3253 	}
3254 	memset(&suspend, 0, sizeof(suspend));
3255 	while (--argc > 0) {
3256 		argv++;
3257 		if (argv[0] == NULL) break;
3258 		option = str2val2(argv[0], nm_thresh_param);
3259 		switch (option) {
3260 		case 0x01:   /* get domain scope */
3261 			if ((domain = str2val2(argv[1], nm_domain_vals)) == 0xFF) {
3262 				print_strs(nm_domain_vals, "Domain Scope:", LOG_ERR, 0);
3263 				return -1;
3264 			}
3265 			argc--;
3266 			argv++;
3267 			break;
3268 		case 0x02:   /* policy ID */
3269 			if (str2uchar(argv[1], &policy_id) < 0) {
3270 				lprintf(LOG_ERR,"Policy ID must be a positive integer.\n");
3271 				return -1;
3272 			}
3273 			argc--;
3274 			argv++;
3275 			break;
3276                 case 0xFF:   /* process periods */
3277 			for (i = 0; count < IPMI_NM_SUSPEND_PERIOD_MAX; i += 3, count++) {
3278 				if (argc < 3) {
3279 					lprintf(LOG_ERR,"Error: suspend period requires a start, stop, and repeat values.\n");
3280 					return -1;
3281 				}
3282 				if (str2uchar(argv[i+0], &suspend.period[count].start) < 0) {
3283 					lprintf(LOG_ERR,"suspend start value %d must be 0-239.\n", count);
3284 					return -1;
3285 				}
3286 				if (str2uchar(argv[i+1], &suspend.period[count].stop) < 0) {
3287 					lprintf(LOG_ERR,"suspend stop value %d  must be 0-239.\n", count);
3288 					return -1;
3289 				}
3290 				if (str2uchar(argv[i+2], &suspend.period[count].repeat) < 0) {
3291 					lprintf(LOG_ERR,"suspend repeat value %d unable to convert.\n", count);
3292 					return -1;
3293 				}
3294 				argc -= 3;
3295 				if (argc <= 0)
3296 					break;
3297 			}
3298 			if (argc <= 0)
3299 				break;
3300 			break;
3301                 default:
3302                         break;
3303                 }
3304         }
3305 	if (action == 0x02) /* get */
3306 		return (ipmi_nm_get_suspend(intf, domain, policy_id));
3307 
3308 	suspend.domain = domain;
3309 	suspend.policy_id = policy_id;
3310 	if (_ipmi_nm_set_suspend(intf, &suspend) < 0)
3311 		return -1;
3312 	return 0;
3313 }
3314 /* end nm */
3315 
3316 static int
ipmi_dcmi_set_limit(struct ipmi_intf * intf,int argc,char ** argv)3317 ipmi_dcmi_set_limit(struct ipmi_intf * intf, int argc, char **argv)
3318 {
3319 	int rc = 0;
3320 
3321 	if ( argc == 10) {
3322 		/* Let`s initialize dcmi power parameters */
3323 		struct ipmi_rq req;
3324 		uint8_t data[256];
3325 		uint16_t sample = 0;
3326 		uint16_t limit = 0;
3327 		uint32_t correction = 0;
3328 		struct ipmi_rs *rsp;
3329 
3330 		memset(data, 0, sizeof(data));
3331 		memset(&req, 0, sizeof(req));
3332 
3333 		req.msg.netfn = IPMI_NETFN_DCGRP;
3334 		req.msg.lun = 0x00;
3335 		req.msg.cmd = IPMI_DCMI_SETLMT; /* Set power limit */
3336 		req.msg.data = data; /* Contents above */
3337 		req.msg.data_len =  15;
3338 
3339 		data[0] = IPMI_DCMI; /* Group Extension Identification */
3340 		data[1] = 0x0;  /* reserved */
3341 		data[2] = 0x0;  /* reserved */
3342 		data[3] = 0x0;  /* reserved */
3343 
3344 		/* action */
3345 		switch (str2val2(argv[2], dcmi_pwrmgmt_action_vals)) {
3346 		case 0x00:
3347 			/* no_action */
3348 			data[4] = 0x00;
3349 			break;
3350 		case 0x01:
3351 			/* power_off */
3352 			data[4] = 0x01;
3353 			break;
3354 		case 0x11:
3355 			/* sel_logging*/
3356 			data[4] = 0x11;
3357 			break;
3358 		case 0xFF:
3359 			/* error - not a string we knew what to do with */
3360 			lprintf(LOG_ERR, "Given Action '%s' is invalid.",
3361 				argv[2]);
3362 			return -1;
3363 		}
3364 		/* limit */
3365 		if (str2ushort(argv[4], &limit) != 0) {
3366 			lprintf(LOG_ERR,
3367 				"Given Limit '%s' is invalid.",
3368 				argv[4]);
3369 			return (-1);
3370 		}
3371 		data[5] = limit >> 0;
3372 		data[6] = limit >> 8;
3373 		/* correction */
3374 		if (str2uint(argv[6], &correction) != 0) {
3375 			lprintf(LOG_ERR,
3376 				"Given Correction '%s' is invalid.",
3377 				argv[6]);
3378 			return (-1);
3379 		}
3380 		data[7] = correction >> 0;
3381 		data[8] = correction >> 8;
3382 		data[9] = correction >> 16;
3383 		data[10] = correction >> 24;
3384 		data[11] = 0x00;  /* reserved */
3385 		data[12] = 0x00;  /* reserved */
3386 		/* sample */
3387 		if (str2ushort(argv[8], &sample) != 0) {
3388 			lprintf(LOG_ERR,
3389 				"Given Sample '%s' is invalid.",
3390 				argv[8]);
3391 			return (-1);
3392 		}
3393 		data[13] = sample >> 0;
3394 		data[14] = sample >> 8;
3395 
3396 		rsp = intf->sendrecv(intf, &req);
3397 		if (chk_rsp(rsp)) {
3398 			return -1;
3399 		}
3400 	} else {
3401 		/* loop through each parameter and value until we have neither */
3402 		while ((argv[1] != NULL) && (argv[2] != NULL)) {
3403 			rc = ipmi_dcmi_pwr_slimit(intf, argv[1], argv[2]);
3404 			/* catch any error that the set limit function returned */
3405 			if (rc > 0) {
3406 				print_strs(dcmi_pwrmgmt_set_usage_vals,
3407 					"set_limit <parameter> <value>", LOG_ERR, 0);
3408 				return -1;
3409 			}
3410 			/* the first argument is the command and the second is the
3411 			* value.  Move argv two places; what is now 3 will be 1
3412 			*/
3413 			argv+=2;
3414 		}
3415 	}
3416 	return rc;
3417 }
3418 
3419 static int
ipmi_dcmi_parse_power(struct ipmi_intf * intf,int argc,char ** argv)3420 ipmi_dcmi_parse_power(struct ipmi_intf * intf, int argc, char **argv)
3421 {
3422 	int rc = 0;
3423 	uint8_t sample_time = 0;
3424 	/* power management */
3425 	switch (str2val2(argv[0], dcmi_pwrmgmt_vals)) {
3426 	case 0x00:
3427 	/* get reading */
3428 		if (argv[1] != NULL) {
3429 			if (!(sample_time = str2val2(argv[1], dcmi_sampling_vals))) {
3430 				print_strs(dcmi_sampling_vals,
3431 					"Invalid sample time. Valid times are: ",
3432 					LOG_ERR, 1);
3433 				printf("\n");
3434 				return -1;
3435 			}
3436 		}
3437 		rc = ipmi_dcmi_pwr_rd(intf, sample_time);
3438 		break;
3439 	case 0x01:
3440 		/* get limit */
3441 		/* because the get limit function is also used to
3442 		 * populate unchanged values for the set limit
3443 		 * command it returns an ipmi response structure
3444 		 */
3445 		rc = ipmi_dcmi_pwr_prnt_glimit(intf);
3446 		break;
3447 	case 0x02:
3448 		/* set limit */
3449 		if (argc < 4) {
3450 			print_strs(dcmi_pwrmgmt_set_usage_vals,
3451 				"set_limit <parameter> <value>",
3452 				LOG_ERR, 0);
3453 			return -1;
3454 		}
3455 		if (ipmi_dcmi_set_limit(intf, argc, argv) < 0)
3456 			return -1;
3457 		rc = ipmi_dcmi_pwr_prnt_glimit(intf);
3458 		break;
3459 	case 0x03:
3460 		/* activate */
3461 		rc = ipmi_dcmi_pwr_actdeact(intf, 1);
3462 		break;
3463 	case 0x04:
3464 		/* deactivate */
3465 		rc = ipmi_dcmi_pwr_actdeact(intf, 0);
3466 		break;
3467 	default:
3468 		/* no valid options */
3469 		print_strs(dcmi_pwrmgmt_vals,
3470 			"power <command>", LOG_ERR, 0);
3471 		break;
3472 	}
3473 	return rc;
3474 }
3475 /* end dcmi power command */
3476 
3477 static int
ipmi_dcmi_thermalpolicy(struct ipmi_intf * intf,int argc,char ** argv)3478 ipmi_dcmi_thermalpolicy(struct ipmi_intf * intf, int argc, char **argv)
3479 {
3480 	int rc = 0;
3481 	uint8_t entityID = 0;
3482 	uint8_t entityInst = 0;
3483 	uint8_t persistanceFlag;
3484 	uint8_t actionHardPowerOff;
3485 	uint8_t actionLogToSEL;
3486 	uint8_t tempLimit = 0;
3487 	uint8_t samplingTimeLSB;
3488 	uint8_t samplingTimeMSB;
3489 	uint16_t samplingTime = 0;
3490 	/* Thermal policy get/set */
3491 	/* dcmitool dcmi thermalpolicy get */
3492 	switch (str2val2(argv[1], dcmi_thermalpolicy_vals)) {
3493 	case 0x00:
3494 		if (argc < 4) {
3495 			lprintf(LOG_NOTICE, "Get <entityID> <instanceID>");
3496 			return -1;
3497 		}
3498 		if (str2uchar(argv[2], &entityID) != 0) {
3499 			lprintf(LOG_ERR,
3500 					"Given Entity ID '%s' is invalid.",
3501 					argv[2]);
3502 			return (-1);
3503 		}
3504 		if (str2uchar(argv[3], &entityInst) != 0) {
3505 			lprintf(LOG_ERR,
3506 					"Given Instance ID '%s' is invalid.",
3507 					argv[3]);
3508 			return (-1);
3509 		}
3510 		rc = ipmi_dcmi_getthermalpolicy(intf,  entityID, entityInst);
3511 		break;
3512 	case 0x01:
3513 		if (argc < 4) {
3514 			lprintf(LOG_NOTICE, "Set <entityID> <instanceID>");
3515 			return -1;
3516 		} else if (argc < 9) {
3517 		print_strs(dcmi_thermalpolicy_set_parameters_vals,
3518 				"Set thermalpolicy instance parameters: "
3519 					"<volatile/nonvolatile/disabled> "
3520 					"<poweroff/nopoweroff/disabled> "
3521 					"<sel/nosel/disabled> <templimitByte> <exceptionTime>",
3522 					LOG_ERR, 0);
3523 			return -1;
3524 		}
3525 		if (str2uchar(argv[2], &entityID) != 0) {
3526 			lprintf(LOG_ERR,
3527 					"Given Entity ID '%s' is invalid.",
3528 					argv[2]);
3529 			return (-1);
3530 		}
3531 		if (str2uchar(argv[3], &entityInst) != 0) {
3532 			lprintf(LOG_ERR,
3533 					"Given Instance ID '%s' is invalid.",
3534 					argv[3]);
3535 			return (-1);
3536 		}
3537 		persistanceFlag = (uint8_t) str2val2(argv[4], dcmi_thermalpolicy_set_parameters_vals);
3538 		actionHardPowerOff = (uint8_t) str2val2(argv[5], dcmi_thermalpolicy_set_parameters_vals);
3539 		actionLogToSEL = (uint8_t) str2val2(argv[6], dcmi_thermalpolicy_set_parameters_vals);
3540 		if (str2uchar(argv[7], &tempLimit) != 0) {
3541 			lprintf(LOG_ERR,
3542 					"Given Temp Limit '%s' is invalid.",
3543 					argv[7]);
3544 			return (-1);
3545 		}
3546 		if (str2ushort(argv[8], &samplingTime) != 0) {
3547 			lprintf(LOG_ERR,
3548 					"Given Sampling Time '%s' is invalid.",
3549 					argv[8]);
3550 			return (-1);
3551 		}
3552 		samplingTimeLSB =  (samplingTime & 0xFF);
3553 		samplingTimeMSB = ((samplingTime & 0xFF00) >> 8);
3554 
3555 		rc = ipmi_dcmi_setthermalpolicy(intf,
3556 			entityID,
3557 			entityInst,
3558 			persistanceFlag,
3559 			actionHardPowerOff,
3560 			actionLogToSEL,
3561 			tempLimit,
3562 			samplingTimeLSB,
3563 			samplingTimeMSB);
3564 
3565 		break;
3566 	default:
3567 		print_strs(dcmi_thermalpolicy_vals,
3568 				"thermalpolicy <command>",
3569 				LOG_ERR, 0);
3570 		return -1;
3571 	}
3572 	return rc;
3573 }
3574 
3575 /*  main
3576  *
3577  * @intf:   dcmi interface handler
3578  * @argc:   argument count
3579  * @argv:   argument vector
3580  */
3581 int
ipmi_dcmi_main(struct ipmi_intf * intf,int argc,char ** argv)3582 ipmi_dcmi_main(struct ipmi_intf * intf, int argc, char **argv)
3583 {
3584 	int rc = 0;
3585 	int i;
3586 	struct ipmi_rs *rsp;
3587 
3588 	if ((argc == 0) || (strncmp(argv[0], "help", 4) == 0)) {
3589 		print_strs(dcmi_cmd_vals,
3590 				"Data Center Management Interface commands",
3591 				LOG_ERR, 0);
3592 		return -1;
3593 	}
3594 	/* start the cmd requested */
3595 	switch (str2val2(argv[0], dcmi_cmd_vals)) {
3596 	case 0x00:
3597 		/* discover capabilities*/
3598 		for (i = 1; dcmi_capable_vals[i-1].str != NULL; i++) {
3599 			if (ipmi_dcmi_prnt_getcapabilities(intf, i) < 0) {
3600 				lprintf(LOG_ERR,"Error discovering %s capabilities!\n",
3601 						val2str2(i, dcmi_capable_vals));
3602 				return -1;
3603 			}
3604 		}
3605 		break;
3606 	case 0x01:
3607 		/* power */
3608 		argv++;
3609 		if (argv[0] == NULL) {
3610 			print_strs(dcmi_pwrmgmt_vals, "power <command>",
3611 					LOG_ERR, 0);
3612 			return -1;
3613 		}
3614 		rc = ipmi_dcmi_parse_power(intf, argc, argv);
3615 		break;
3616 		/* end power command */
3617 	case 0x02:
3618 		/* sensor print */
3619 		/* Look for each item in the dcmi_discvry_snsr_vals struct
3620 		 * and if it exists, print the sdr record id(s) for it.
3621 		 * Use the val from each one as the sensor number.
3622 		 */
3623 		for (i = 0; dcmi_discvry_snsr_vals[i].str != NULL; i++) {
3624 			/* get all of the information about this sensor */
3625 			rc = ipmi_dcmi_prnt_discvry_snsr(intf,
3626 					dcmi_discvry_snsr_vals[i].val);
3627 		}
3628 		break;
3629 		/* end sensor print */
3630 	case 0x03:
3631 		/* asset tag */
3632 		if(ipmi_dcmi_prnt_getassettag(intf) < 0) {
3633 			lprintf(LOG_ERR, "Error getting asset tag!");
3634 			return -1;
3635 		}
3636 		break;
3637 		/* end asset tag */
3638 	case 0x04:
3639 	{
3640 		/* set asset tag */
3641 		if (argc == 1 ) {
3642 			print_strs(dcmi_cmd_vals,
3643 					"Data Center Management Interface commands",
3644 					LOG_ERR, 0);
3645 			return -1;
3646 		}
3647 		if (ipmi_dcmi_prnt_setassettag(intf, (uint8_t *)argv[1]) < 0) {
3648 			lprintf(LOG_ERR, "\nError setting asset tag!");
3649 			return -1;
3650 		}
3651 		break;
3652 	}
3653 	/* end set asset tag */
3654 	case 0x05:
3655 		/* get management controller identifier string */
3656 		if (ipmi_dcmi_prnt_getmngctrlids(intf) < 0) {
3657 			lprintf(LOG_ERR,
3658 					"Error getting management controller identifier string!");
3659 			return -1;
3660 		}
3661 		break;
3662 		/* end get management controller identifier string */
3663 	case 0x06:
3664 	{
3665 		/* set management controller identifier string */
3666 		if (argc == 1 ) {
3667 			print_strs(dcmi_cmd_vals,
3668 					"Data Center Management Interface commands",
3669 					LOG_ERR, 0);
3670 			return -1;
3671 		}
3672 		if (ipmi_dcmi_prnt_setmngctrlids(intf, (uint8_t *)argv[1]) < 0) {
3673 			lprintf(LOG_ERR,
3674 					"Error setting management controller identifier string!");
3675 			return -1;
3676 		}
3677 		break;
3678 	}
3679 	/* end set management controller identifier string */
3680 	case 0x07:
3681 		/* get/set thermal policy */
3682 		rc = ipmi_dcmi_thermalpolicy(intf, argc, argv);
3683 		break;
3684 	case 0x08:
3685 		if(ipmi_dcmi_prnt_get_temp_readings(intf) < 0 ) {
3686 			lprintf(LOG_ERR,
3687 					"Error get temperature readings!");
3688 			return -1;
3689 		}
3690 		break;
3691 	case 0x09:
3692 		if(ipmi_dcmi_prnt_getconfparam(intf) < 0 ) {
3693 			lprintf(LOG_ERR,
3694 					"Error Get DCMI Configuration Parameters!");
3695 			return -1;
3696 		};
3697 		break;
3698 	case 0x0A:
3699 	{
3700 		switch (argc) {
3701 		case 2:
3702 			if (strncmp(argv[1], "activate_dhcp", 13) != 0) {
3703 				print_strs( dcmi_conf_param_vals,
3704 						"DCMI Configuration Parameters",
3705 						LOG_ERR, 0);
3706 				return -1;
3707 			}
3708 			break;
3709 		default:
3710 			if (argc != 3 || strncmp(argv[1], "help", 4) == 0) {
3711 				print_strs(dcmi_conf_param_vals,
3712 						"DCMI Configuration Parameters",
3713 						LOG_ERR, 0);
3714 				return -1;
3715 			}
3716 		}
3717 		if (strncmp(argv[1], "activate_dhcp", 13) == 0) {
3718 			rsp = ipmi_dcmi_setconfparam(intf, 1, 1);
3719 		} else {
3720 			uint16_t tmp_val = 0;
3721 			if (str2ushort(argv[2], &tmp_val) != 0) {
3722 				lprintf(LOG_ERR,
3723 						"Given %s '%s' is invalid.",
3724 						argv[1], argv[2]);
3725 				return (-1);
3726 			}
3727 			rsp = ipmi_dcmi_setconfparam(intf,
3728 					str2val2(argv[1], dcmi_conf_param_vals),
3729 					tmp_val);
3730 		}
3731 		if (chk_rsp(rsp)) {
3732 			lprintf(LOG_ERR,
3733 					"Error Set DCMI Configuration Parameters!");
3734 		}
3735 		break;
3736 	}
3737 	case 0x0B:
3738 	{
3739 		if (intf->session == NULL) {
3740 			lprintf(LOG_ERR,
3741 					"\nOOB discovery is available only via RMCP interface.");
3742 			return -1;
3743 		}
3744 		if(ipmi_dcmi_prnt_oobDiscover(intf) < 0) {
3745 			lprintf(LOG_ERR, "\nOOB discovering capabilities failed.");
3746 			return -1;
3747 		}
3748 		break;
3749 	}
3750 	default:
3751 		/* couldn't detect what the user entered */
3752 		print_strs(dcmi_cmd_vals,
3753 				"Data Center Management Interface commands",
3754 				LOG_ERR, 0);
3755 		return -1;
3756 		break;
3757 	}
3758 	printf("\n");
3759 	return rc;
3760 }
3761 
3762 /*  Node Manager main
3763  *
3764  * @intf:   nm interface handler
3765  * @argc:   argument count
3766  * @argv:   argument vector
3767  */
3768 int
ipmi_nm_main(struct ipmi_intf * intf,int argc,char ** argv)3769 ipmi_nm_main(struct ipmi_intf * intf, int argc, char **argv)
3770 {
3771 	struct nm_discover disc;
3772 
3773 	if ((argc == 0) || (strncmp(argv[0], "help", 4) == 0)) {
3774 		print_strs(nm_cmd_vals,
3775 			"Node Manager Interface commands",
3776 			LOG_ERR, 0);
3777 		return -1;
3778 	}
3779 
3780 	switch (str2val2(argv[0], nm_cmd_vals)) {
3781 	/* discover */
3782 	case 0x00:
3783 		if (_ipmi_nm_discover(intf, &disc))
3784 			return -1;
3785 		printf("    Node Manager Version %s\n", val2str2(disc.nm_version, nm_version_vals));
3786 		printf("    revision %d.%d%d  patch version %d\n", disc.major_rev,
3787 				disc.minor_rev>>4, disc.minor_rev&0xf, disc.patch_version);
3788 		break;
3789 	/* capability */
3790 	case 0x01:
3791 		if (ipmi_nm_getcapabilities(intf, argc, argv))
3792 			return -1;
3793 		break;
3794 	/*  policy control enable-disable */
3795 	case 0x02:
3796 		if (ipmi_nm_control(intf, argc, argv))
3797 			return -1;
3798 		break;
3799 	/* policy */
3800 	case 0x03:
3801 		if (ipmi_nm_policy(intf, argc, argv))
3802 			return -1;
3803 		break;
3804 	/* Get statistics */
3805 	case 0x04:
3806 		if (ipmi_nm_get_statistics(intf, argc, argv))
3807 			return -1;
3808 		break;
3809 	/* set power draw range */
3810 	case 0x05:
3811 		if (ipmi_nm_set_range(intf, argc, argv))
3812 			return -1;
3813 		break;
3814 	/* set/get suspend periods */
3815 	case 0x06:
3816 		if (ipmi_nm_suspend(intf, argc, argv))
3817 			return -1;
3818 		break;
3819 	/* reset statistics */
3820 	case 0x07:
3821 		if (ipmi_nm_reset_statistics(intf, argc, argv))
3822 			return -1;
3823 		break;
3824 	/* set/get alert destination */
3825 	case 0x08:
3826 		if (ipmi_nm_alert(intf, argc, argv))
3827 			return -1;
3828 		break;
3829 	/* set/get alert thresholds */
3830 	case 0x09:
3831 		if (ipmi_nm_thresh(intf, argc, argv))
3832 			return -1;
3833 		break;
3834 	default:
3835 		print_strs(nm_cmd_vals, "Node Manager Interface commands", LOG_ERR, 0);
3836 		break;
3837 	}
3838 	return 0;
3839 }
3840 
3841 /* Display DCMI sensor information
3842  * Uses the ipmi_sdr_get_next_header to read SDR header and compare to the
3843  * target Record ID. Then either ipmi_sensor_print_full or
3844  * ipmi_sensor_print_compact is called to print the data
3845  *
3846  * @intf:   ipmi interface handler
3847  * @rec_id: target Record ID
3848  */
3849 static int
ipmi_print_sensor_info(struct ipmi_intf * intf,uint16_t rec_id)3850 ipmi_print_sensor_info(struct ipmi_intf *intf, uint16_t rec_id)
3851 {
3852 	struct sdr_get_rs *header;
3853 	struct ipmi_sdr_iterator *itr;
3854 	int rc = 0;
3855 	uint8_t *rec = NULL;
3856 
3857 	itr = ipmi_sdr_start(intf, 0);
3858 	if (itr == NULL) {
3859 		lprintf(LOG_ERR, "Unable to open SDR for reading");
3860 		return (-1);
3861 	}
3862 
3863 	while ((header = ipmi_sdr_get_next_header(intf, itr)) != NULL) {
3864 		if (header->id == rec_id) {
3865 			break;
3866 		}
3867 	}
3868 	if (header == NULL) {
3869 		lprintf(LOG_DEBUG, "header == NULL");
3870 		ipmi_sdr_end(intf, itr);
3871 		return (-1);
3872 	}
3873 	/* yes, we found the SDR for this record ID, now get full record */
3874 	rec = ipmi_sdr_get_record(intf, header, itr);
3875 	if (rec == NULL) {
3876 		lprintf(LOG_DEBUG, "rec == NULL");
3877 		ipmi_sdr_end(intf, itr);
3878 		return (-1);
3879 	}
3880 	if ((header->type == SDR_RECORD_TYPE_FULL_SENSOR) ||
3881 			(header->type == SDR_RECORD_TYPE_COMPACT_SENSOR)) {
3882 		rc = ipmi_sdr_print_rawentry(intf, header->type,
3883 				rec, header->length);
3884 	} else {
3885 		rc = (-1);
3886 	}
3887 	free(rec);
3888 	rec = NULL;
3889 	ipmi_sdr_end(intf, itr);
3890 	return rc;
3891 }
3892