blob: 501d8cbc473a7131dbeb8cddcd74ab4d7aee0142 [file] [log] [blame]
Vijay Khemkae7d23d02019-03-08 13:13:40 -08001/*
2 * Copyright (c) 2018-present Facebook. All Rights Reserved.
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#include <host-ipmid/ipmid-api.h>
Vijay Khemkacc0d6d92019-08-27 14:51:17 -070018#include <nlohmann/json.hpp>
Vijay Khemka317999d2020-01-02 13:43:42 -080019#include <ipmid/api.hpp>
Vijay Khemkae7d23d02019-03-08 13:13:40 -080020#include <stdbool.h>
21#include <stdio.h>
22#include <sys/stat.h>
23
24#include <fstream>
25#include <iostream>
Vijay Khemka427b2762019-12-12 12:49:25 -080026#include <sstream>
Vijay Khemka74106e82019-12-12 13:42:34 -080027#include <iomanip>
Vijay Khemkacc0d6d92019-08-27 14:51:17 -070028#include <phosphor-logging/log.hpp>
Vijay Khemka317999d2020-01-02 13:43:42 -080029#include <sdbusplus/asio/connection.hpp>
Vijay Khemka88884b82019-08-27 15:23:07 -070030#include <appcommands.hpp>
Vijay Khemkae7d23d02019-03-08 13:13:40 -080031
32namespace ipmi
33{
34
Vijay Khemka11b33a02019-12-13 12:04:20 -080035#define JSON_POST_DATA_FILE "/usr/share/lcd-debug/post_desc.json"
36#define JSON_GPIO_DATA_FILE "/usr/share/lcd-debug/gpio_desc.json"
Vijay Khemka427b2762019-12-12 12:49:25 -080037#define JSON_SENSOR_NAMES_FILE "/usr/share/lcd-debug/cri_sensors.json"
Vijay Khemka11b33a02019-12-13 12:04:20 -080038
Vijay Khemkae7d23d02019-03-08 13:13:40 -080039#define ETH_INTF_NAME "eth0"
40
41#define ESCAPE "\x1B"
42#define ESC_BAT ESCAPE "B"
43#define ESC_MCU_BL_VER ESCAPE "U"
44#define ESC_MCU_RUN_VER ESCAPE "R"
45#define ESC_ALT ESCAPE "[5;7m"
46#define ESC_RST ESCAPE "[m"
47
48#define LINE_DELIMITER '\x1F'
49
50#define FRAME_BUFF_SIZE 4096
51#define FRAME_PAGE_BUF_SIZE 256
52#define FRU_ALL 0
53#define MAX_VALUE_LEN 64
54
Vijay Khemka38183d62019-08-28 16:19:33 -070055#define DEBUG_GPIO_KEY "GpioDesc"
56#define GPIO_ARRAY_SIZE 4
57#define GPIO_PIN_INDEX 0
58#define GPIO_LEVEL_INDEX 1
59#define GPIO_DEF_INDEX 2
60#define GPIO_DESC_INDEX 3
61
Vijay Khemkae7d23d02019-03-08 13:13:40 -080062/* Used for systems which do not specifically have a
63 * phase, and we want to ignore the phase provided by the
64 * debug card */
65#define PHASE_ANY 0xff
66
67ipmi_ret_t getNetworkData(uint8_t lan_param, char *data);
68int8_t getFruData(std::string &serial, std::string &name);
69
Vijay Khemka427b2762019-12-12 12:49:25 -080070/* Declare storage functions used here */
71namespace storage
72{
73int getSensorValue(std::string &, double &);
Vijay Khemka58bd5d82019-12-13 11:05:56 -080074int getSensorUnit(std::string &, std::string &);
75} // namespace storage
Vijay Khemka427b2762019-12-12 12:49:25 -080076
Vijay Khemka317999d2020-01-02 13:43:42 -080077static constexpr bool DEBUG = false;
78static const uint8_t meAddress = 1;
79static constexpr uint8_t lun = 0;
80
81using IpmbMethodType =
82 std::tuple<int, uint8_t, uint8_t, uint8_t, uint8_t, std::vector<uint8_t>>;
83
Vijay Khemkae7d23d02019-03-08 13:13:40 -080084typedef struct _sensor_desc
85{
86 char name[16];
87 uint8_t sensor_num;
88 char unit[5];
89 uint8_t fru;
90 uint8_t disp_prec;
91} sensor_desc_t;
92
93struct frame
94{
95 char title[32];
96 size_t max_size;
97 size_t max_page;
98 char *buf;
99 uint16_t idx_head, idx_tail;
100 uint8_t line_per_page;
101 uint8_t line_width;
102 uint16_t lines, pages;
103 uint8_t esc_sts;
104 uint8_t overwrite;
105 time_t mtime;
106 frame() : buf(NULL), pages(0), mtime(0)
107 {
108 }
109 int init(size_t size);
110 int append(const char *string, int indent);
111 int insert(const char *string, int indent);
112 int getPage(int page, char *page_buf, size_t page_buf_size);
113 int isFull();
114 int isEscSeq(char chr);
115 int parse(char *buf, size_t buf_size, const char *input, int indent);
116};
117
118struct frame frame_info;
119struct frame frame_sel;
120struct frame frame_snr;
121
122enum ENUM_PANEL
123{
124 PANEL_MAIN = 1,
125 PANEL_BOOT_ORDER = 2,
126 PANEL_POWER_POLICY = 3,
127};
128
129struct ctrl_panel
130{
131 uint8_t parent;
132 uint8_t item_num;
133 char item_str[8][32];
134 uint8_t (*select)(uint8_t item);
135};
136
137static uint8_t panel_main(uint8_t item);
138static uint8_t panel_boot_order(uint8_t item);
139static uint8_t panel_power_policy(uint8_t item);
140
141static struct ctrl_panel panels[] = {
142 {/* dummy entry for making other to 1-based */},
143 {
144 .parent = PANEL_MAIN,
145 .item_num = 2,
146 .item_str =
147 {
148 "User Setting",
149 ">Boot Order",
150 ">Power Policy",
151 },
152 .select = panel_main,
153 },
154 {
155 .parent = PANEL_MAIN,
156 .item_num = 0,
157 .item_str =
158 {
159 "Boot Order",
160 },
161 .select = panel_boot_order,
162 },
163 {
164 .parent = PANEL_MAIN,
165 .item_num = 0,
166 .item_str =
167 {
168 "Power Policy",
169 },
170 .select = panel_power_policy,
171 },
172};
173
174static int panelNum = (sizeof(panels) / sizeof(struct ctrl_panel)) - 1;
175
176/* Returns the FRU the hand-switch is switched to. If it is switched to BMC
177 * it returns FRU_ALL. Note, if in err, it returns FRU_ALL */
178static uint8_t plat_get_fru_sel()
179{
180 // For Tiogapass it just return 1, can modify to support more platform
181 return 1;
182}
183
184// return 0 on seccuess
185int frame::init(size_t size)
186{
187 // Reset status
188 idx_head = idx_tail = 0;
189 lines = 0;
190 esc_sts = 0;
191 pages = 1;
192
193 if (buf != NULL && max_size == size)
194 {
195 // reinit
196 return 0;
197 }
198
199 if (buf != NULL && max_size != size)
200 {
201 delete[] buf;
202 }
203 // Initialize Configuration
204 title[0] = '\0';
205 buf = new char[size];
206 max_size = size;
207 max_page = size;
208 line_per_page = 7;
209 line_width = 16;
210 overwrite = 0;
211
212 if (buf)
213 return 0;
214 else
215 return -1;
216}
217
218// return 0 on seccuess
219int frame::append(const char *string, int indent)
220{
221 const size_t buf_size = 64;
222 char lbuf[buf_size];
223 char *ptr;
224 int ret;
225
226 ret = parse(lbuf, buf_size, string, indent);
227
228 if (ret < 0)
229 return ret;
230
231 int len = strlen(string);
232 for (ptr = lbuf; *ptr != '\0'; ptr++)
233 {
234 if (isFull())
235 {
236 if (overwrite)
237 {
238 if (buf[idx_head] == LINE_DELIMITER)
239 lines--;
240 idx_head = (idx_head + 1) % max_size;
241 }
242 else
243 return -1;
244 }
245
246 buf[idx_tail] = *ptr;
247 if (*ptr == LINE_DELIMITER)
248 lines++;
249
250 idx_tail = (idx_tail + 1) % max_size;
251 }
252
253 pages = (lines / line_per_page) + ((lines % line_per_page) ? 1 : 0);
254
255 if (pages > max_page)
256 pages = max_page;
257
258 return 0;
259}
260
261// return 0 on seccuess
262int frame::insert(const char *string, int indent)
263{
264 const size_t buf_size = 128;
265 char lbuf[buf_size];
266 char *ptr;
267 int ret;
268 int i;
269
270 ret = parse(lbuf, buf_size, string, indent);
271
272 if (ret < 0)
273 return ret;
274
275 for (i = strlen(lbuf) - 1; i >= 0; i--)
276 {
277 ptr = &lbuf[i];
278 if (isFull())
279 {
280 if (overwrite)
281 {
282 idx_tail = (idx_tail + max_size - 1) % max_size;
283 if (buf[idx_tail] == LINE_DELIMITER)
284 lines--;
285 }
286 else
287 return -1;
288 }
289
290 idx_head = (idx_head + max_size - 1) % max_size;
291
292 buf[idx_head] = *ptr;
293 if (*ptr == LINE_DELIMITER)
294 lines++;
295 }
296
297 pages = (lines / line_per_page) + ((lines % line_per_page) ? 1 : 0);
298
299 if (pages > max_page)
300 pages = max_page;
301
302 return 0;
303}
304
305// return page size
306int frame::getPage(int page, char *page_buf, size_t page_buf_size)
307{
308 int ret;
309 uint16_t line = 0;
310 uint16_t idx, len;
311
312 if (buf == NULL)
313 return -1;
314
315 // 1-based page
316 if (page > pages || page < 1)
317 return -1;
318
319 if (page_buf == NULL || page_buf_size < 0)
320 return -1;
321
322 ret = snprintf(page_buf, 17, "%-10s %02d/%02d", title, page, pages);
323 len = strlen(page_buf);
324 if (ret < 0)
325 return -1;
326
327 line = 0;
328 idx = idx_head;
329 while (line < ((page - 1) * line_per_page) && idx != idx_tail)
330 {
331 if (buf[idx] == LINE_DELIMITER)
332 line++;
333 idx = (idx + 1) % max_size;
334 }
335
336 while (line < ((page)*line_per_page) && idx != idx_tail)
337 {
338 if (buf[idx] == LINE_DELIMITER)
339 {
340 line++;
341 }
342 else
343 {
344 page_buf[len++] = buf[idx];
345 if (len == (page_buf_size - 1))
346 {
347 break;
348 }
349 }
350 idx = (idx + 1) % max_size;
351 }
352
353 return len;
354}
355
356// return 1 for frame buffer full
357int frame::isFull()
358{
359 if (buf == NULL)
360 return -1;
361
362 if ((idx_tail + 1) % max_size == idx_head)
363 return 1;
364 else
365 return 0;
366}
367
368// return 1 for Escape Sequence
369int frame::isEscSeq(char chr)
370{
371 uint8_t curr_sts = esc_sts;
372
373 if (esc_sts == 0 && (chr == 0x1b))
374 esc_sts = 1; // Escape Sequence
375 else if (esc_sts == 1 && (chr == 0x5b))
376 esc_sts = 2; // Control Sequence Introducer(CSI)
377 else if (esc_sts == 1 && (chr != 0x5b))
378 esc_sts = 0;
379 else if (esc_sts == 2 && (chr >= 0x40 && chr <= 0x7e))
380 esc_sts = 0;
381
382 if (curr_sts || esc_sts)
383 return 1;
384 else
385 return 0;
386}
387
388// return 0 on success
389int frame::parse(char *lbuf, size_t buf_size, const char *input, int indent)
390{
391 uint8_t pos, esc;
392 int i;
393 const char *in, *end;
394
395 if (buf == NULL || input == NULL)
396 return -1;
397
398 if (indent >= line_width || indent < 0)
399 return -1;
400
401 in = input;
402 end = in + strlen(input);
403 pos = 0; // line position
404 esc = 0; // escape state
405 i = 0; // buf index
406 while (in != end)
407 {
408 if (i >= buf_size)
409 break;
410
411 if (pos < indent)
412 {
413 // fill indent
414 lbuf[i++] = ' ';
415 pos++;
416 continue;
417 }
418
419 esc = isEscSeq(*in);
420
421 if (!esc && pos == line_width)
422 {
423 lbuf[i++] = LINE_DELIMITER;
424 pos = 0;
425 continue;
426 }
427
428 if (!esc)
429 pos++;
430
431 // fill input data
432 lbuf[i++] = *(in++);
433 }
434
435 // padding
436 while (pos <= line_width)
437 {
438 if (i >= buf_size)
439 break;
440 if (pos < line_width)
441 lbuf[i++] = ' ';
442 else
443 lbuf[i++] = LINE_DELIMITER;
444 pos++;
445 }
446
447 // full
448 if (i >= buf_size)
449 return -1;
450
451 lbuf[i++] = '\0';
452
453 return 0;
454}
455
456static int chk_cri_sel_update(uint8_t *cri_sel_up)
457{
458 FILE *fp;
459 struct stat file_stat;
460 uint8_t pos = plat_get_fru_sel();
461 static uint8_t pre_pos = 0xff;
462
463 fp = fopen("/mnt/data/cri_sel", "r");
464 if (fp)
465 {
466 if ((stat("/mnt/data/cri_sel", &file_stat) == 0) &&
467 (file_stat.st_mtime != frame_sel.mtime || pre_pos != pos))
468 {
469 *cri_sel_up = 1;
470 }
471 else
472 {
473 *cri_sel_up = 0;
474 }
475 fclose(fp);
476 }
477 else
478 {
479 if (frame_sel.buf == NULL || frame_sel.lines != 0 || pre_pos != pos)
480 {
481 *cri_sel_up = 1;
482 }
483 else
484 {
485 *cri_sel_up = 0;
486 }
487 }
488 pre_pos = pos;
489 return 0;
490}
491
492int plat_udbg_get_frame_info(uint8_t *num)
493{
494 *num = 3;
495 return 0;
496}
497
498int plat_udbg_get_updated_frames(uint8_t *count, uint8_t *buffer)
499{
500 uint8_t cri_sel_up = 0;
501 uint8_t info_page_up = 1;
502
503 *count = 0;
504
505 // info page update
506 if (info_page_up == 1)
507 {
508 buffer[*count] = 1;
509 *count += 1;
510 }
511
512 // cri sel update
513 chk_cri_sel_update(&cri_sel_up);
514 if (cri_sel_up == 1)
515 {
516 buffer[*count] = 2;
517 *count += 1;
518 }
519
520 // cri sensor update
521 buffer[*count] = 3;
522 *count += 1;
523
524 return 0;
525}
526
527int plat_udbg_get_post_desc(uint8_t index, uint8_t *next, uint8_t phase,
528 uint8_t *end, uint8_t *length, uint8_t *buffer)
529{
Vijay Khemkacc0d6d92019-08-27 14:51:17 -0700530 nlohmann::json postObj;
531 std::string postCode;
Vijay Khemkae7d23d02019-03-08 13:13:40 -0800532
Vijay Khemkacc0d6d92019-08-27 14:51:17 -0700533 /* Get post description data stored in json file */
534 std::ifstream file(JSON_POST_DATA_FILE);
535 if (file)
536 {
537 file >> postObj;
538 file.close();
539 }
540 else
541 {
542 phosphor::logging::log<phosphor::logging::level::ERR>(
543 "Post code description file not found",
544 phosphor::logging::entry("POST_CODE_FILE=%s", JSON_POST_DATA_FILE));
545 return -1;
546 }
547
548 std::string phaseStr = "PhaseAny";
549 if (postObj.find(phaseStr) == postObj.end())
550 {
551 phaseStr = "Phase" + std::to_string(phase);
552 }
553
554 if (postObj.find(phaseStr) == postObj.end())
555 {
556 phosphor::logging::log<phosphor::logging::level::ERR>(
557 "Post code phase not available",
558 phosphor::logging::entry("PHASE=%d", phase));
559 return -1;
560 }
561
562 auto phaseObj = postObj[phaseStr];
563 int phaseSize = phaseObj.size();
564
565 for (int i = 0; i < phaseSize; i++)
566 {
567 postCode = phaseObj[i][0];
568 if (index == stoul(postCode, nullptr, 16))
569 {
570 std::string postDesc = phaseObj[i][1];
571 *length = postDesc.size();
572 memcpy(buffer, postDesc.data(), *length);
573 buffer[*length] = '\0';
574
575 if (phaseSize != i + 1)
576 {
577 postCode = phaseObj[i + 1][0];
578 *next = stoul(postCode, nullptr, 16);
579 *end = 0;
580 }
581 else
582 {
583 if (postObj.size() != phase)
584 {
585 std::string nextPhaseStr =
586 "Phase" + std::to_string(phase + 1);
587 postCode = postObj[nextPhaseStr][0][0];
588 *next = stoul(postCode, nullptr, 16);
589 *end = 0;
590 }
591 else
592 {
593 *next = 0xff;
594 *end = 1;
595 }
596 }
597
598 return 0;
599 }
600 }
601
602 phosphor::logging::log<phosphor::logging::level::ERR>(
603 "Post code description data not available",
604 phosphor::logging::entry("PHASE_CODE=%d_0x%x", phase, index));
605 return -1;
Vijay Khemkae7d23d02019-03-08 13:13:40 -0800606}
607
Vijay Khemkae7d23d02019-03-08 13:13:40 -0800608int plat_udbg_get_gpio_desc(uint8_t index, uint8_t *next, uint8_t *level,
Vijay Khemka38183d62019-08-28 16:19:33 -0700609 uint8_t *def, uint8_t *length, uint8_t *buffer)
Vijay Khemkae7d23d02019-03-08 13:13:40 -0800610{
Vijay Khemka38183d62019-08-28 16:19:33 -0700611 nlohmann::json gpioObj;
612 std::string gpioPin;
613
614 /* Get gpio data stored in json file */
615 std::ifstream file(JSON_GPIO_DATA_FILE);
616 if (file)
617 {
618 file >> gpioObj;
619 file.close();
620 }
621 else
622 {
623 phosphor::logging::log<phosphor::logging::level::ERR>(
624 "GPIO pin description file not found",
625 phosphor::logging::entry("GPIO_PIN_DETAILS_FILE=%s",
626 JSON_GPIO_DATA_FILE));
627 return -1;
628 }
629
630 if (gpioObj.find(DEBUG_GPIO_KEY) == gpioObj.end())
631 {
632 phosphor::logging::log<phosphor::logging::level::ERR>(
633 "GPIO pin details not available",
634 phosphor::logging::entry("GPIO_JSON_KEY=%d", DEBUG_GPIO_KEY));
635 return -1;
636 }
637
638 auto obj = gpioObj[DEBUG_GPIO_KEY];
639 int objSize = obj.size();
640
641 for (int i = 0; i < objSize; i++)
642 {
643 if (obj[i].size() != GPIO_ARRAY_SIZE)
644 {
645 phosphor::logging::log<phosphor::logging::level::ERR>(
646 "Size of gpio array is incorrect",
647 phosphor::logging::entry("EXPECTED_SIZE=%d", GPIO_ARRAY_SIZE));
648 return -1;
649 }
650
651 gpioPin = obj[i][GPIO_PIN_INDEX];
652 if (index == stoul(gpioPin, nullptr, 16))
653 {
654 if (objSize != i + 1)
655 {
656 gpioPin = obj[i + 1][GPIO_PIN_INDEX];
657 *next = stoul(gpioPin, nullptr, 16);
658 }
659 else
660 {
661 *next = 0xff;
662 }
663
664 *level = obj[i][GPIO_LEVEL_INDEX];
665 *def = obj[i][GPIO_DEF_INDEX];
666 std::string gpioDesc = obj[i][GPIO_DESC_INDEX];
667 *length = gpioDesc.size();
668 memcpy(buffer, gpioDesc.data(), *length);
669 buffer[*length] = '\0';
670
671 return 0;
672 }
673 }
674
675 phosphor::logging::log<phosphor::logging::level::ERR>(
676 "GPIO pin description data not available",
677 phosphor::logging::entry("GPIO_PIN=0x%x", index));
678 return -1;
Vijay Khemkae7d23d02019-03-08 13:13:40 -0800679}
680
681static int udbg_get_cri_sel(uint8_t frame, uint8_t page, uint8_t *next,
682 uint8_t *count, uint8_t *buffer)
683{
684 int len;
685 int ret;
686 char line_buff[FRAME_PAGE_BUF_SIZE], *fptr;
687 const char *ptr;
688 FILE *fp;
689 struct stat file_stat;
690 uint8_t pos = plat_get_fru_sel();
691 static uint8_t pre_pos = FRU_ALL;
692 bool pos_changed = pre_pos != pos;
693
694 pre_pos = pos;
695
696 /* Revisit this */
697 fp = fopen("/mnt/data/cri_sel", "r");
698 if (fp)
699 {
700 if ((stat("/mnt/data/cri_sel", &file_stat) == 0) &&
701 (file_stat.st_mtime != frame_sel.mtime || pos_changed))
702 {
703 // initialize and clear frame
704 frame_sel.init(FRAME_BUFF_SIZE);
705 frame_sel.overwrite = 1;
706 frame_sel.max_page = 20;
707 frame_sel.mtime = file_stat.st_mtime;
708 snprintf(frame_sel.title, 32, "Cri SEL");
709
710 while (fgets(line_buff, FRAME_PAGE_BUF_SIZE, fp))
711 {
712 // Remove newline
713 line_buff[strlen(line_buff) - 1] = '\0';
714 ptr = line_buff;
715 // Find message
716 ptr = strstr(ptr, "local0.err");
717 if (ptr == NULL)
718 {
719 continue;
720 }
721
722 if ((ptr = strrchr(ptr, ':')) == NULL)
723 {
724 continue;
725 }
726 len = strlen(ptr);
727 if (len > 2)
728 {
729 // to skip log string ": "
730 ptr += 2;
731 }
732 // Write new message
733 frame_sel.insert(ptr, 0);
734 }
735 }
736 fclose(fp);
737 }
738 else
739 {
740 // Title only
741 frame_sel.init(FRAME_BUFF_SIZE);
742 snprintf(frame_sel.title, 32, "Cri SEL");
743 frame_sel.mtime = 0;
744 }
745
746 if (page > frame_sel.pages)
747 {
748 return -1;
749 }
750
751 ret = frame_sel.getPage(page, (char *)buffer, FRAME_PAGE_BUF_SIZE);
752 if (ret < 0)
753 {
754 *count = 0;
755 return -1;
756 }
757 *count = (uint8_t)ret;
758
759 if (page < frame_sel.pages)
760 *next = page + 1;
761 else
762 *next = 0xFF; // Set the value of next to 0xFF to indicate this is the
763 // last page
764
765 return 0;
766}
767
768static int udbg_get_cri_sensor(uint8_t frame, uint8_t page, uint8_t *next,
769 uint8_t *count, uint8_t *buffer)
770{
Vijay Khemka427b2762019-12-12 12:49:25 -0800771 int ret;
772 double fvalue;
Vijay Khemkae7d23d02019-03-08 13:13:40 -0800773
774 if (page == 1)
775 {
776 // Only update frame data while getting page 1
777
778 // initialize and clear frame
779 frame_snr.init(FRAME_BUFF_SIZE);
780 snprintf(frame_snr.title, 32, "CriSensor");
Vijay Khemka427b2762019-12-12 12:49:25 -0800781
782 nlohmann::json senObj;
783
784 /* Get critical sensor names stored in json file */
785 std::ifstream file(JSON_SENSOR_NAMES_FILE);
786 if (file)
787 {
788 file >> senObj;
789 file.close();
790 }
791 else
792 {
793 phosphor::logging::log<phosphor::logging::level::ERR>(
794 "Critical Sensor names file not found",
795 phosphor::logging::entry("CRI_SENSOR_NAMES_FILE=%s",
796 JSON_SENSOR_NAMES_FILE));
797 return -1;
798 }
799
800 /* Get sensors values for all critical sensors */
801 for (auto &j : senObj.items())
802 {
803 std::string senName = j.key();
804 auto val = j.value();
805
806 if (ipmi::storage::getSensorValue(senName, fvalue) == 0)
807 {
808 std::stringstream ss;
Vijay Khemkaf43fad42019-12-26 11:47:58 -0800809 int prec = 0; // Default value
810
811 if (val.find("precision") != val.end())
812 prec = val["precision"];
813
814 ss << std::fixed << std::setprecision(prec) << fvalue;
Vijay Khemka427b2762019-12-12 12:49:25 -0800815
816 std::string senStr;
817 if (val.find("short_name") != val.end())
818 senStr = val["short_name"];
819 else
820 senStr = senName;
821
822 senStr += ss.str();
Vijay Khemka58bd5d82019-12-13 11:05:56 -0800823
824 /* Get unit string for sensor and append in output */
825 std::string unitStr;
826 if (ipmi::storage::getSensorUnit(senName, unitStr) == 0)
827 senStr += unitStr;
828
Vijay Khemka427b2762019-12-12 12:49:25 -0800829 frame_snr.append(senStr.c_str(), 0);
830 }
831 else
832 {
833 phosphor::logging::log<phosphor::logging::level::INFO>(
834 "Critical sensor not found",
835 phosphor::logging::entry("CRI_SENSOR_NAME=%s",
836 senName.c_str()));
837 }
838 }
839
Vijay Khemkae7d23d02019-03-08 13:13:40 -0800840 } // End of update frame
841
842 if (page > frame_snr.pages)
843 {
844 return -1;
845 }
846
847 ret = frame_snr.getPage(page, (char *)buffer, FRAME_PAGE_BUF_SIZE);
848 if (ret < 0)
849 {
850 *count = 0;
851 return -1;
852 }
853 *count = (uint8_t)ret;
854
855 if (page < frame_snr.pages)
856 *next = page + 1;
857 else
858 *next = 0xFF; // Set the value of next to 0xFF to indicate this is the
859 // last page
860
861 return 0;
862}
863
Vijay Khemka88884b82019-08-27 15:23:07 -0700864static int getBiosVer(std::string &ver)
865{
866 nlohmann::json appObj;
867
868 std::ifstream file(JSON_APP_DATA_FILE);
869 if (file)
870 {
871 file >> appObj;
872 file.close();
873 if (appObj.find(KEY_SYSFW_VER) != appObj.end())
874 {
875 ver = appObj[KEY_SYSFW_VER].get<std::string>();
876 return 0;
877 }
878 }
879
880 return -1;
881}
882
Vijay Khemkadd14c0f2020-03-18 14:48:13 -0700883int sendMeCmd(uint8_t netFn, uint8_t cmd, std::vector<uint8_t> &cmdData,
884 std::vector<uint8_t> &respData)
885{
886 auto bus = getSdBus();
887
888 if (DEBUG)
889 {
890 std::cout << "ME NetFn:cmd " << (int)netFn << ":" << (int)cmd << "\n";
891 std::cout << "ME req data: ";
892 for (auto d : cmdData)
893 {
894 std::cout << d << " ";
895 }
896 std::cout << "\n";
897 }
898
899 auto method = bus->new_method_call("xyz.openbmc_project.Ipmi.Channel.Ipmb",
900 "/xyz/openbmc_project/Ipmi/Channel/Ipmb",
901 "org.openbmc.Ipmb", "sendRequest");
902 method.append(meAddress, netFn, lun, cmd, cmdData);
903
904 auto reply = bus->call(method);
905 if (reply.is_method_error())
906 {
907 phosphor::logging::log<phosphor::logging::level::ERR>(
908 "Error reading from ME");
909 return -1;
910 }
911
912 IpmbMethodType resp;
913 reply.read(resp);
914
915 respData =
916 std::move(std::get<std::remove_reference_t<decltype(respData)>>(resp));
917
918 if (DEBUG)
919 {
920 std::cout << "ME resp data: ";
921 for (auto d : respData)
922 {
923 std::cout << d << " ";
924 }
925 std::cout << "\n";
926 }
927
928 return 0;
929}
930
Vijay Khemka317999d2020-01-02 13:43:42 -0800931static int getMeStatus(std::string &status)
932{
933 uint8_t cmd = 0x01; // Get Device id command
934 uint8_t netFn = 0x06; // Netfn for APP
935 std::shared_ptr<sdbusplus::asio::connection> bus = getSdBus();
936 std::vector<uint8_t> cmdData;
937
938 auto method = bus->new_method_call("xyz.openbmc_project.Ipmi.Channel.Ipmb",
939 "/xyz/openbmc_project/Ipmi/Channel/Ipmb",
940 "org.openbmc.Ipmb", "sendRequest");
941 method.append(meAddress, netFn, lun, cmd, cmdData);
942
943 auto reply = bus->call(method);
944 if (reply.is_method_error())
945 {
946 std::cerr << "Error reading from ME\n";
947 return -1;
948 }
949
950 IpmbMethodType resp;
951 reply.read(resp);
952
953 std::vector<uint8_t> data;
954 data = std::get<5>(resp);
955
956 if (DEBUG)
957 {
958 std::cout << "ME Get ID: ";
959 for (size_t d : data)
960 {
961 std::cout << d << " ";
962 }
963 std::cout << "\n";
964 }
965
966 if (data[2] & 0x80)
967 status = "recovery mode";
968 else
969 status = "operation mode";
970
971 return 0;
972}
973
Vijay Khemkae7d23d02019-03-08 13:13:40 -0800974static int udbg_get_info_page(uint8_t frame, uint8_t page, uint8_t *next,
975 uint8_t *count, uint8_t *buffer)
976{
977 char line_buff[1000], *pres_dev = line_buff;
978 uint8_t pos = plat_get_fru_sel();
979 const char *delim = "\n";
980 int ret;
981 std::string serialName = "BOARD_SERIAL_NUMBER";
982 std::string partName = "BOARD_PART_NUMBER";
983 std::string verDel = "VERSION=";
984 std::string verPath = "/etc/os-release";
985
986 if (page == 1)
987 {
988 // Only update frame data while getting page 1
989
990 // initialize and clear frame
991 frame_info.init(FRAME_BUFF_SIZE);
992 snprintf(frame_info.title, 32, "SYS_Info");
993
994 // FRU TBD:
995 std::string data;
996 frame_info.append("SN:", 0);
997 if (getFruData(data, serialName) != 0)
998 {
999 data = "Not Found";
1000 }
1001 frame_info.append(data.c_str(), 1);
1002 frame_info.append("PN:", 0);
1003 if (getFruData(data, partName) != 0)
1004 {
1005 data = "Not Found";
1006 }
1007 frame_info.append(data.c_str(), 1);
1008
1009 // LAN
1010 getNetworkData(3, line_buff);
1011 frame_info.append("BMC_IP:", 0);
1012 frame_info.append(line_buff, 1);
1013 getNetworkData(59, line_buff);
1014 frame_info.append("BMC_IPv6:", 0);
1015 frame_info.append(line_buff, 1);
1016
1017 // BMC ver
1018 std::ifstream file(verPath);
1019 if (file)
1020 {
1021 std::string line;
1022 while (std::getline(file, line))
1023 {
1024 if (line.find(verDel) != std::string::npos)
1025 {
1026 std::string bmcVer = line.substr(verDel.size());
1027 frame_info.append("BMC_FW_ver:", 0);
1028 frame_info.append(bmcVer.c_str(), 1);
1029 break;
1030 }
1031 }
1032 }
1033
Vijay Khemkae7d23d02019-03-08 13:13:40 -08001034 // BIOS ver
Vijay Khemka88884b82019-08-27 15:23:07 -07001035 std::string biosVer;
1036 if (getBiosVer(biosVer) == 0)
1037 {
1038 frame_info.append("BIOS_FW_ver:", 0);
1039 frame_info.append(biosVer.c_str(), 1);
1040 }
Vijay Khemkae7d23d02019-03-08 13:13:40 -08001041
Vijay Khemkae7d23d02019-03-08 13:13:40 -08001042 // ME status
Vijay Khemka317999d2020-01-02 13:43:42 -08001043 std::string meStatus;
1044 if (getMeStatus(meStatus) != 0)
1045 {
1046 phosphor::logging::log<phosphor::logging::level::WARNING>(
1047 "Reading ME status failed");
1048 meStatus = "unknown";
1049 }
1050 frame_info.append("ME_status:", 0);
1051 frame_info.append(meStatus.c_str(), 1);
Vijay Khemkae7d23d02019-03-08 13:13:40 -08001052
Vijay Khemka317999d2020-01-02 13:43:42 -08001053 /* TBD: Board ID needs implementation */
Vijay Khemkae7d23d02019-03-08 13:13:40 -08001054 // Board ID
1055
1056 // Battery - Use Escape sequence
1057 frame_info.append("Battery:", 0);
1058 frame_info.append(ESC_BAT " ", 1);
1059 // frame_info.append(&frame_info, esc_bat, 1);
1060
1061 // MCU Version - Use Escape sequence
1062 frame_info.append("MCUbl_ver:", 0);
1063 frame_info.append(ESC_MCU_BL_VER, 1);
1064 frame_info.append("MCU_ver:", 0);
1065 frame_info.append(ESC_MCU_RUN_VER, 1);
1066
1067 // TBD:
1068 // Sys config present device
1069
1070 } // End of update frame
1071
1072 if (page > frame_info.pages)
1073 {
1074 return -1;
1075 }
1076
1077 ret = frame_info.getPage(page, (char *)buffer, FRAME_PAGE_BUF_SIZE);
1078 if (ret < 0)
1079 {
1080 *count = 0;
1081 return -1;
1082 }
1083 *count = (uint8_t)ret;
1084
1085 if (page < frame_info.pages)
1086 *next = page + 1;
1087 else
1088 *next = 0xFF; // Set the value of next to 0xFF to indicate this is the
1089 // last page
1090
1091 return 0;
1092}
1093
1094int plat_udbg_get_frame_data(uint8_t frame, uint8_t page, uint8_t *next,
1095 uint8_t *count, uint8_t *buffer)
1096{
1097 switch (frame)
1098 {
1099 case 1: // info_page
1100 return udbg_get_info_page(frame, page, next, count, buffer);
1101 case 2: // critical SEL
1102 return udbg_get_cri_sel(frame, page, next, count, buffer);
1103 case 3: // critical Sensor
1104 return udbg_get_cri_sensor(frame, page, next, count, buffer);
1105 default:
1106 return -1;
1107 }
1108}
1109
1110static uint8_t panel_main(uint8_t item)
1111{
1112 // Update item list when select item 0
1113 switch (item)
1114 {
1115 case 1:
1116 return panels[PANEL_BOOT_ORDER].select(0);
1117 case 2:
1118 return panels[PANEL_POWER_POLICY].select(0);
1119 default:
1120 return PANEL_MAIN;
1121 }
1122}
1123
1124static uint8_t panel_boot_order(uint8_t item)
1125{
1126 int i;
1127 unsigned char buff[MAX_VALUE_LEN], pickup, len;
1128 uint8_t pos = plat_get_fru_sel();
1129
1130 /* To be implemented */
1131 /*
1132 if (pos != FRU_ALL && pal_get_boot_order(pos, buff, buff, &len) == 0)
1133 {
1134 if (item > 0 && item < SIZE_BOOT_ORDER)
1135 {
1136 pickup = buff[item];
1137 while (item > 1)
1138 {
1139 buff[item] = buff[item -1];
1140 item--;
1141 }
1142 buff[item] = pickup;
1143 buff[0] |= 0x80;
1144 pal_set_boot_order(pos, buff, buff, &len);
1145
1146 // refresh items
1147 return panels[PANEL_BOOT_ORDER].select(0);
1148 }
1149
1150 // '*': boot flags valid, BIOS has not yet read
1151 snprintf(panels[PANEL_BOOT_ORDER].item_str[0], 32,
1152 "Boot Order%c", (buff[0] & 0x80)?'*':'\0');
1153
1154 for (i = 1; i < SIZE_BOOT_ORDER; i++)
1155 {
1156 switch (buff[i])
1157 {
1158 case 0x0:
1159 snprintf(panels[PANEL_BOOT_ORDER].item_str[i], 32,
1160 " USB device");
1161 break;
1162 case 0x1:
1163 snprintf(panels[PANEL_BOOT_ORDER].item_str[i], 32,
1164 " Network v4");
1165 break;
1166 case (0x1 | 0x8):
1167 snprintf(panels[PANEL_BOOT_ORDER].item_str[i], 32,
1168 " Network v6");
1169 break;
1170 case 0x2:
1171 snprintf(panels[PANEL_BOOT_ORDER].item_str[i], 32,
1172 " SATA HDD");
1173 break;
1174 case 0x3:
1175 snprintf(panels[PANEL_BOOT_ORDER].item_str[i], 32,
1176 " SATA-CDROM");
1177 break;
1178 case 0x4:
1179 snprintf(panels[PANEL_BOOT_ORDER].item_str[i], 32,
1180 " Other");
1181 break;
1182 default:
1183 panels[PANEL_BOOT_ORDER].item_str[i][0] = '\0';
1184 break;
1185 }
1186 }
1187
1188 // remove empty items
1189 for (i--; (strlen(panels[PANEL_BOOT_ORDER].item_str[i]) == 0) && (i > 0); i--)
1190 ;
1191
1192 panels[PANEL_BOOT_ORDER].item_num = i;
1193 } else
1194 {
1195 panels[PANEL_BOOT_ORDER].item_num = 0;
1196 }
1197 */
1198 return PANEL_BOOT_ORDER;
1199}
1200
1201static uint8_t panel_power_policy(uint8_t item)
1202{
1203 uint8_t buff[32] = {0};
1204 uint8_t res_len;
1205 uint8_t pos = plat_get_fru_sel();
1206 uint8_t policy;
1207 // uint8_t pwr_policy_item_map[3] = {POWER_CFG_ON, POWER_CFG_LPS,
1208 // POWER_CFG_OFF};
1209
1210 /* To be cleaned */
1211 /*
1212 if (pos != FRU_ALL) {
1213 if (item > 0 && item <= sizeof(pwr_policy_item_map)) {
1214 policy = pwr_policy_item_map[item - 1];
1215 pal_set_power_restore_policy(pos, &policy, NULL);
1216 }
1217 pal_get_chassis_status(pos, NULL, buff, &res_len);
1218 policy = (((uint8_t)buff[0]) >> 5) & 0x7;
1219 snprintf(panels[PANEL_POWER_POLICY].item_str[1], 32,
1220 "%cPower On", policy == POWER_CFG_ON ? '*' : ' ');
1221 snprintf(panels[PANEL_POWER_POLICY].item_str[2], 32,
1222 "%cLast State", policy == POWER_CFG_LPS ? '*' : ' ');
1223 snprintf(panels[PANEL_POWER_POLICY].item_str[3], 32,
1224 "%cPower Off", policy == POWER_CFG_OFF ? '*' : ' ');
1225 panels[PANEL_POWER_POLICY].item_num = 3;
1226 } else {
1227 panels[PANEL_POWER_POLICY].item_num = 0;
1228 }
1229 */
1230 return PANEL_POWER_POLICY;
1231}
1232
1233int plat_udbg_control_panel(uint8_t panel, uint8_t operation, uint8_t item,
1234 uint8_t *count, uint8_t *buffer)
1235{
1236 if (panel > panelNum || panel < PANEL_MAIN)
1237 return IPMI_CC_PARM_OUT_OF_RANGE;
1238
1239 // No more item; End of item list
1240 if (item > panels[panel].item_num)
1241 return IPMI_CC_PARM_OUT_OF_RANGE;
1242
1243 switch (operation)
1244 {
1245 case 0: // Get Description
1246 break;
1247 case 1: // Select item
1248 panel = panels[panel].select(item);
1249 item = 0;
1250 break;
1251 case 2: // Back
1252 panel = panels[panel].parent;
1253 item = 0;
1254 break;
1255 default:
1256 return IPMI_CC_PARM_OUT_OF_RANGE;
1257 }
1258
1259 buffer[0] = panel;
1260 buffer[1] = item;
1261 buffer[2] = strlen(panels[panel].item_str[item]);
1262 if (buffer[2] > 0 && (buffer[2] + 3) < FRAME_PAGE_BUF_SIZE)
1263 {
1264 memcpy(&buffer[3], panels[panel].item_str[item], buffer[2]);
1265 }
1266 *count = buffer[2] + 3;
1267 return IPMI_CC_OK;
1268}
1269
1270} // end of namespace ipmi