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