blob: 19e791496eb8fdcc05c7f3f01f4335c15369946a [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 Khemka317999d2020-01-02 13:43:42 -0800883static int getMeStatus(std::string &status)
884{
885 uint8_t cmd = 0x01; // Get Device id command
886 uint8_t netFn = 0x06; // Netfn for APP
887 std::shared_ptr<sdbusplus::asio::connection> bus = getSdBus();
888 std::vector<uint8_t> cmdData;
889
890 auto method = bus->new_method_call("xyz.openbmc_project.Ipmi.Channel.Ipmb",
891 "/xyz/openbmc_project/Ipmi/Channel/Ipmb",
892 "org.openbmc.Ipmb", "sendRequest");
893 method.append(meAddress, netFn, lun, cmd, cmdData);
894
895 auto reply = bus->call(method);
896 if (reply.is_method_error())
897 {
898 std::cerr << "Error reading from ME\n";
899 return -1;
900 }
901
902 IpmbMethodType resp;
903 reply.read(resp);
904
905 std::vector<uint8_t> data;
906 data = std::get<5>(resp);
907
908 if (DEBUG)
909 {
910 std::cout << "ME Get ID: ";
911 for (size_t d : data)
912 {
913 std::cout << d << " ";
914 }
915 std::cout << "\n";
916 }
917
918 if (data[2] & 0x80)
919 status = "recovery mode";
920 else
921 status = "operation mode";
922
923 return 0;
924}
925
Vijay Khemkae7d23d02019-03-08 13:13:40 -0800926static int udbg_get_info_page(uint8_t frame, uint8_t page, uint8_t *next,
927 uint8_t *count, uint8_t *buffer)
928{
929 char line_buff[1000], *pres_dev = line_buff;
930 uint8_t pos = plat_get_fru_sel();
931 const char *delim = "\n";
932 int ret;
933 std::string serialName = "BOARD_SERIAL_NUMBER";
934 std::string partName = "BOARD_PART_NUMBER";
935 std::string verDel = "VERSION=";
936 std::string verPath = "/etc/os-release";
937
938 if (page == 1)
939 {
940 // Only update frame data while getting page 1
941
942 // initialize and clear frame
943 frame_info.init(FRAME_BUFF_SIZE);
944 snprintf(frame_info.title, 32, "SYS_Info");
945
946 // FRU TBD:
947 std::string data;
948 frame_info.append("SN:", 0);
949 if (getFruData(data, serialName) != 0)
950 {
951 data = "Not Found";
952 }
953 frame_info.append(data.c_str(), 1);
954 frame_info.append("PN:", 0);
955 if (getFruData(data, partName) != 0)
956 {
957 data = "Not Found";
958 }
959 frame_info.append(data.c_str(), 1);
960
961 // LAN
962 getNetworkData(3, line_buff);
963 frame_info.append("BMC_IP:", 0);
964 frame_info.append(line_buff, 1);
965 getNetworkData(59, line_buff);
966 frame_info.append("BMC_IPv6:", 0);
967 frame_info.append(line_buff, 1);
968
969 // BMC ver
970 std::ifstream file(verPath);
971 if (file)
972 {
973 std::string line;
974 while (std::getline(file, line))
975 {
976 if (line.find(verDel) != std::string::npos)
977 {
978 std::string bmcVer = line.substr(verDel.size());
979 frame_info.append("BMC_FW_ver:", 0);
980 frame_info.append(bmcVer.c_str(), 1);
981 break;
982 }
983 }
984 }
985
Vijay Khemkae7d23d02019-03-08 13:13:40 -0800986 // BIOS ver
Vijay Khemka88884b82019-08-27 15:23:07 -0700987 std::string biosVer;
988 if (getBiosVer(biosVer) == 0)
989 {
990 frame_info.append("BIOS_FW_ver:", 0);
991 frame_info.append(biosVer.c_str(), 1);
992 }
Vijay Khemkae7d23d02019-03-08 13:13:40 -0800993
Vijay Khemkae7d23d02019-03-08 13:13:40 -0800994 // ME status
Vijay Khemka317999d2020-01-02 13:43:42 -0800995 std::string meStatus;
996 if (getMeStatus(meStatus) != 0)
997 {
998 phosphor::logging::log<phosphor::logging::level::WARNING>(
999 "Reading ME status failed");
1000 meStatus = "unknown";
1001 }
1002 frame_info.append("ME_status:", 0);
1003 frame_info.append(meStatus.c_str(), 1);
Vijay Khemkae7d23d02019-03-08 13:13:40 -08001004
Vijay Khemka317999d2020-01-02 13:43:42 -08001005 /* TBD: Board ID needs implementation */
Vijay Khemkae7d23d02019-03-08 13:13:40 -08001006 // Board ID
1007
1008 // Battery - Use Escape sequence
1009 frame_info.append("Battery:", 0);
1010 frame_info.append(ESC_BAT " ", 1);
1011 // frame_info.append(&frame_info, esc_bat, 1);
1012
1013 // MCU Version - Use Escape sequence
1014 frame_info.append("MCUbl_ver:", 0);
1015 frame_info.append(ESC_MCU_BL_VER, 1);
1016 frame_info.append("MCU_ver:", 0);
1017 frame_info.append(ESC_MCU_RUN_VER, 1);
1018
1019 // TBD:
1020 // Sys config present device
1021
1022 } // End of update frame
1023
1024 if (page > frame_info.pages)
1025 {
1026 return -1;
1027 }
1028
1029 ret = frame_info.getPage(page, (char *)buffer, FRAME_PAGE_BUF_SIZE);
1030 if (ret < 0)
1031 {
1032 *count = 0;
1033 return -1;
1034 }
1035 *count = (uint8_t)ret;
1036
1037 if (page < frame_info.pages)
1038 *next = page + 1;
1039 else
1040 *next = 0xFF; // Set the value of next to 0xFF to indicate this is the
1041 // last page
1042
1043 return 0;
1044}
1045
1046int plat_udbg_get_frame_data(uint8_t frame, uint8_t page, uint8_t *next,
1047 uint8_t *count, uint8_t *buffer)
1048{
1049 switch (frame)
1050 {
1051 case 1: // info_page
1052 return udbg_get_info_page(frame, page, next, count, buffer);
1053 case 2: // critical SEL
1054 return udbg_get_cri_sel(frame, page, next, count, buffer);
1055 case 3: // critical Sensor
1056 return udbg_get_cri_sensor(frame, page, next, count, buffer);
1057 default:
1058 return -1;
1059 }
1060}
1061
1062static uint8_t panel_main(uint8_t item)
1063{
1064 // Update item list when select item 0
1065 switch (item)
1066 {
1067 case 1:
1068 return panels[PANEL_BOOT_ORDER].select(0);
1069 case 2:
1070 return panels[PANEL_POWER_POLICY].select(0);
1071 default:
1072 return PANEL_MAIN;
1073 }
1074}
1075
1076static uint8_t panel_boot_order(uint8_t item)
1077{
1078 int i;
1079 unsigned char buff[MAX_VALUE_LEN], pickup, len;
1080 uint8_t pos = plat_get_fru_sel();
1081
1082 /* To be implemented */
1083 /*
1084 if (pos != FRU_ALL && pal_get_boot_order(pos, buff, buff, &len) == 0)
1085 {
1086 if (item > 0 && item < SIZE_BOOT_ORDER)
1087 {
1088 pickup = buff[item];
1089 while (item > 1)
1090 {
1091 buff[item] = buff[item -1];
1092 item--;
1093 }
1094 buff[item] = pickup;
1095 buff[0] |= 0x80;
1096 pal_set_boot_order(pos, buff, buff, &len);
1097
1098 // refresh items
1099 return panels[PANEL_BOOT_ORDER].select(0);
1100 }
1101
1102 // '*': boot flags valid, BIOS has not yet read
1103 snprintf(panels[PANEL_BOOT_ORDER].item_str[0], 32,
1104 "Boot Order%c", (buff[0] & 0x80)?'*':'\0');
1105
1106 for (i = 1; i < SIZE_BOOT_ORDER; i++)
1107 {
1108 switch (buff[i])
1109 {
1110 case 0x0:
1111 snprintf(panels[PANEL_BOOT_ORDER].item_str[i], 32,
1112 " USB device");
1113 break;
1114 case 0x1:
1115 snprintf(panels[PANEL_BOOT_ORDER].item_str[i], 32,
1116 " Network v4");
1117 break;
1118 case (0x1 | 0x8):
1119 snprintf(panels[PANEL_BOOT_ORDER].item_str[i], 32,
1120 " Network v6");
1121 break;
1122 case 0x2:
1123 snprintf(panels[PANEL_BOOT_ORDER].item_str[i], 32,
1124 " SATA HDD");
1125 break;
1126 case 0x3:
1127 snprintf(panels[PANEL_BOOT_ORDER].item_str[i], 32,
1128 " SATA-CDROM");
1129 break;
1130 case 0x4:
1131 snprintf(panels[PANEL_BOOT_ORDER].item_str[i], 32,
1132 " Other");
1133 break;
1134 default:
1135 panels[PANEL_BOOT_ORDER].item_str[i][0] = '\0';
1136 break;
1137 }
1138 }
1139
1140 // remove empty items
1141 for (i--; (strlen(panels[PANEL_BOOT_ORDER].item_str[i]) == 0) && (i > 0); i--)
1142 ;
1143
1144 panels[PANEL_BOOT_ORDER].item_num = i;
1145 } else
1146 {
1147 panels[PANEL_BOOT_ORDER].item_num = 0;
1148 }
1149 */
1150 return PANEL_BOOT_ORDER;
1151}
1152
1153static uint8_t panel_power_policy(uint8_t item)
1154{
1155 uint8_t buff[32] = {0};
1156 uint8_t res_len;
1157 uint8_t pos = plat_get_fru_sel();
1158 uint8_t policy;
1159 // uint8_t pwr_policy_item_map[3] = {POWER_CFG_ON, POWER_CFG_LPS,
1160 // POWER_CFG_OFF};
1161
1162 /* To be cleaned */
1163 /*
1164 if (pos != FRU_ALL) {
1165 if (item > 0 && item <= sizeof(pwr_policy_item_map)) {
1166 policy = pwr_policy_item_map[item - 1];
1167 pal_set_power_restore_policy(pos, &policy, NULL);
1168 }
1169 pal_get_chassis_status(pos, NULL, buff, &res_len);
1170 policy = (((uint8_t)buff[0]) >> 5) & 0x7;
1171 snprintf(panels[PANEL_POWER_POLICY].item_str[1], 32,
1172 "%cPower On", policy == POWER_CFG_ON ? '*' : ' ');
1173 snprintf(panels[PANEL_POWER_POLICY].item_str[2], 32,
1174 "%cLast State", policy == POWER_CFG_LPS ? '*' : ' ');
1175 snprintf(panels[PANEL_POWER_POLICY].item_str[3], 32,
1176 "%cPower Off", policy == POWER_CFG_OFF ? '*' : ' ');
1177 panels[PANEL_POWER_POLICY].item_num = 3;
1178 } else {
1179 panels[PANEL_POWER_POLICY].item_num = 0;
1180 }
1181 */
1182 return PANEL_POWER_POLICY;
1183}
1184
1185int plat_udbg_control_panel(uint8_t panel, uint8_t operation, uint8_t item,
1186 uint8_t *count, uint8_t *buffer)
1187{
1188 if (panel > panelNum || panel < PANEL_MAIN)
1189 return IPMI_CC_PARM_OUT_OF_RANGE;
1190
1191 // No more item; End of item list
1192 if (item > panels[panel].item_num)
1193 return IPMI_CC_PARM_OUT_OF_RANGE;
1194
1195 switch (operation)
1196 {
1197 case 0: // Get Description
1198 break;
1199 case 1: // Select item
1200 panel = panels[panel].select(item);
1201 item = 0;
1202 break;
1203 case 2: // Back
1204 panel = panels[panel].parent;
1205 item = 0;
1206 break;
1207 default:
1208 return IPMI_CC_PARM_OUT_OF_RANGE;
1209 }
1210
1211 buffer[0] = panel;
1212 buffer[1] = item;
1213 buffer[2] = strlen(panels[panel].item_str[item]);
1214 if (buffer[2] > 0 && (buffer[2] + 3) < FRAME_PAGE_BUF_SIZE)
1215 {
1216 memcpy(&buffer[3], panels[panel].item_str[item], buffer[2]);
1217 }
1218 *count = buffer[2] + 3;
1219 return IPMI_CC_OK;
1220}
1221
1222} // end of namespace ipmi