blob: dc6522e10d6a1bc04422d55d4ca9f8d7e5f2a1c6 [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 Khemkae7d23d02019-03-08 13:13:40 -080019#include <stdbool.h>
20#include <stdio.h>
21#include <sys/stat.h>
22
23#include <fstream>
24#include <iostream>
Vijay Khemka427b2762019-12-12 12:49:25 -080025#include <sstream>
Vijay Khemkacc0d6d92019-08-27 14:51:17 -070026#include <phosphor-logging/log.hpp>
Vijay Khemka88884b82019-08-27 15:23:07 -070027#include <appcommands.hpp>
Vijay Khemkae7d23d02019-03-08 13:13:40 -080028
29namespace ipmi
30{
31
Vijay Khemka11b33a02019-12-13 12:04:20 -080032#define JSON_POST_DATA_FILE "/usr/share/lcd-debug/post_desc.json"
33#define JSON_GPIO_DATA_FILE "/usr/share/lcd-debug/gpio_desc.json"
Vijay Khemka427b2762019-12-12 12:49:25 -080034#define JSON_SENSOR_NAMES_FILE "/usr/share/lcd-debug/cri_sensors.json"
Vijay Khemka11b33a02019-12-13 12:04:20 -080035
Vijay Khemkae7d23d02019-03-08 13:13:40 -080036#define ETH_INTF_NAME "eth0"
37
38#define ESCAPE "\x1B"
39#define ESC_BAT ESCAPE "B"
40#define ESC_MCU_BL_VER ESCAPE "U"
41#define ESC_MCU_RUN_VER ESCAPE "R"
42#define ESC_ALT ESCAPE "[5;7m"
43#define ESC_RST ESCAPE "[m"
44
45#define LINE_DELIMITER '\x1F'
46
47#define FRAME_BUFF_SIZE 4096
48#define FRAME_PAGE_BUF_SIZE 256
49#define FRU_ALL 0
50#define MAX_VALUE_LEN 64
51
Vijay Khemka38183d62019-08-28 16:19:33 -070052#define DEBUG_GPIO_KEY "GpioDesc"
53#define GPIO_ARRAY_SIZE 4
54#define GPIO_PIN_INDEX 0
55#define GPIO_LEVEL_INDEX 1
56#define GPIO_DEF_INDEX 2
57#define GPIO_DESC_INDEX 3
58
Vijay Khemkae7d23d02019-03-08 13:13:40 -080059/* Used for systems which do not specifically have a
60 * phase, and we want to ignore the phase provided by the
61 * debug card */
62#define PHASE_ANY 0xff
63
64ipmi_ret_t getNetworkData(uint8_t lan_param, char *data);
65int8_t getFruData(std::string &serial, std::string &name);
66
Vijay Khemka427b2762019-12-12 12:49:25 -080067/* Declare storage functions used here */
68namespace storage
69{
70int getSensorValue(std::string &, double &);
71}
72
Vijay Khemkae7d23d02019-03-08 13:13:40 -080073typedef struct _sensor_desc
74{
75 char name[16];
76 uint8_t sensor_num;
77 char unit[5];
78 uint8_t fru;
79 uint8_t disp_prec;
80} sensor_desc_t;
81
82struct frame
83{
84 char title[32];
85 size_t max_size;
86 size_t max_page;
87 char *buf;
88 uint16_t idx_head, idx_tail;
89 uint8_t line_per_page;
90 uint8_t line_width;
91 uint16_t lines, pages;
92 uint8_t esc_sts;
93 uint8_t overwrite;
94 time_t mtime;
95 frame() : buf(NULL), pages(0), mtime(0)
96 {
97 }
98 int init(size_t size);
99 int append(const char *string, int indent);
100 int insert(const char *string, int indent);
101 int getPage(int page, char *page_buf, size_t page_buf_size);
102 int isFull();
103 int isEscSeq(char chr);
104 int parse(char *buf, size_t buf_size, const char *input, int indent);
105};
106
107struct frame frame_info;
108struct frame frame_sel;
109struct frame frame_snr;
110
111enum ENUM_PANEL
112{
113 PANEL_MAIN = 1,
114 PANEL_BOOT_ORDER = 2,
115 PANEL_POWER_POLICY = 3,
116};
117
118struct ctrl_panel
119{
120 uint8_t parent;
121 uint8_t item_num;
122 char item_str[8][32];
123 uint8_t (*select)(uint8_t item);
124};
125
126static uint8_t panel_main(uint8_t item);
127static uint8_t panel_boot_order(uint8_t item);
128static uint8_t panel_power_policy(uint8_t item);
129
130static struct ctrl_panel panels[] = {
131 {/* dummy entry for making other to 1-based */},
132 {
133 .parent = PANEL_MAIN,
134 .item_num = 2,
135 .item_str =
136 {
137 "User Setting",
138 ">Boot Order",
139 ">Power Policy",
140 },
141 .select = panel_main,
142 },
143 {
144 .parent = PANEL_MAIN,
145 .item_num = 0,
146 .item_str =
147 {
148 "Boot Order",
149 },
150 .select = panel_boot_order,
151 },
152 {
153 .parent = PANEL_MAIN,
154 .item_num = 0,
155 .item_str =
156 {
157 "Power Policy",
158 },
159 .select = panel_power_policy,
160 },
161};
162
163static int panelNum = (sizeof(panels) / sizeof(struct ctrl_panel)) - 1;
164
165/* Returns the FRU the hand-switch is switched to. If it is switched to BMC
166 * it returns FRU_ALL. Note, if in err, it returns FRU_ALL */
167static uint8_t plat_get_fru_sel()
168{
169 // For Tiogapass it just return 1, can modify to support more platform
170 return 1;
171}
172
173// return 0 on seccuess
174int frame::init(size_t size)
175{
176 // Reset status
177 idx_head = idx_tail = 0;
178 lines = 0;
179 esc_sts = 0;
180 pages = 1;
181
182 if (buf != NULL && max_size == size)
183 {
184 // reinit
185 return 0;
186 }
187
188 if (buf != NULL && max_size != size)
189 {
190 delete[] buf;
191 }
192 // Initialize Configuration
193 title[0] = '\0';
194 buf = new char[size];
195 max_size = size;
196 max_page = size;
197 line_per_page = 7;
198 line_width = 16;
199 overwrite = 0;
200
201 if (buf)
202 return 0;
203 else
204 return -1;
205}
206
207// return 0 on seccuess
208int frame::append(const char *string, int indent)
209{
210 const size_t buf_size = 64;
211 char lbuf[buf_size];
212 char *ptr;
213 int ret;
214
215 ret = parse(lbuf, buf_size, string, indent);
216
217 if (ret < 0)
218 return ret;
219
220 int len = strlen(string);
221 for (ptr = lbuf; *ptr != '\0'; ptr++)
222 {
223 if (isFull())
224 {
225 if (overwrite)
226 {
227 if (buf[idx_head] == LINE_DELIMITER)
228 lines--;
229 idx_head = (idx_head + 1) % max_size;
230 }
231 else
232 return -1;
233 }
234
235 buf[idx_tail] = *ptr;
236 if (*ptr == LINE_DELIMITER)
237 lines++;
238
239 idx_tail = (idx_tail + 1) % max_size;
240 }
241
242 pages = (lines / line_per_page) + ((lines % line_per_page) ? 1 : 0);
243
244 if (pages > max_page)
245 pages = max_page;
246
247 return 0;
248}
249
250// return 0 on seccuess
251int frame::insert(const char *string, int indent)
252{
253 const size_t buf_size = 128;
254 char lbuf[buf_size];
255 char *ptr;
256 int ret;
257 int i;
258
259 ret = parse(lbuf, buf_size, string, indent);
260
261 if (ret < 0)
262 return ret;
263
264 for (i = strlen(lbuf) - 1; i >= 0; i--)
265 {
266 ptr = &lbuf[i];
267 if (isFull())
268 {
269 if (overwrite)
270 {
271 idx_tail = (idx_tail + max_size - 1) % max_size;
272 if (buf[idx_tail] == LINE_DELIMITER)
273 lines--;
274 }
275 else
276 return -1;
277 }
278
279 idx_head = (idx_head + max_size - 1) % max_size;
280
281 buf[idx_head] = *ptr;
282 if (*ptr == LINE_DELIMITER)
283 lines++;
284 }
285
286 pages = (lines / line_per_page) + ((lines % line_per_page) ? 1 : 0);
287
288 if (pages > max_page)
289 pages = max_page;
290
291 return 0;
292}
293
294// return page size
295int frame::getPage(int page, char *page_buf, size_t page_buf_size)
296{
297 int ret;
298 uint16_t line = 0;
299 uint16_t idx, len;
300
301 if (buf == NULL)
302 return -1;
303
304 // 1-based page
305 if (page > pages || page < 1)
306 return -1;
307
308 if (page_buf == NULL || page_buf_size < 0)
309 return -1;
310
311 ret = snprintf(page_buf, 17, "%-10s %02d/%02d", title, page, pages);
312 len = strlen(page_buf);
313 if (ret < 0)
314 return -1;
315
316 line = 0;
317 idx = idx_head;
318 while (line < ((page - 1) * line_per_page) && idx != idx_tail)
319 {
320 if (buf[idx] == LINE_DELIMITER)
321 line++;
322 idx = (idx + 1) % max_size;
323 }
324
325 while (line < ((page)*line_per_page) && idx != idx_tail)
326 {
327 if (buf[idx] == LINE_DELIMITER)
328 {
329 line++;
330 }
331 else
332 {
333 page_buf[len++] = buf[idx];
334 if (len == (page_buf_size - 1))
335 {
336 break;
337 }
338 }
339 idx = (idx + 1) % max_size;
340 }
341
342 return len;
343}
344
345// return 1 for frame buffer full
346int frame::isFull()
347{
348 if (buf == NULL)
349 return -1;
350
351 if ((idx_tail + 1) % max_size == idx_head)
352 return 1;
353 else
354 return 0;
355}
356
357// return 1 for Escape Sequence
358int frame::isEscSeq(char chr)
359{
360 uint8_t curr_sts = esc_sts;
361
362 if (esc_sts == 0 && (chr == 0x1b))
363 esc_sts = 1; // Escape Sequence
364 else if (esc_sts == 1 && (chr == 0x5b))
365 esc_sts = 2; // Control Sequence Introducer(CSI)
366 else if (esc_sts == 1 && (chr != 0x5b))
367 esc_sts = 0;
368 else if (esc_sts == 2 && (chr >= 0x40 && chr <= 0x7e))
369 esc_sts = 0;
370
371 if (curr_sts || esc_sts)
372 return 1;
373 else
374 return 0;
375}
376
377// return 0 on success
378int frame::parse(char *lbuf, size_t buf_size, const char *input, int indent)
379{
380 uint8_t pos, esc;
381 int i;
382 const char *in, *end;
383
384 if (buf == NULL || input == NULL)
385 return -1;
386
387 if (indent >= line_width || indent < 0)
388 return -1;
389
390 in = input;
391 end = in + strlen(input);
392 pos = 0; // line position
393 esc = 0; // escape state
394 i = 0; // buf index
395 while (in != end)
396 {
397 if (i >= buf_size)
398 break;
399
400 if (pos < indent)
401 {
402 // fill indent
403 lbuf[i++] = ' ';
404 pos++;
405 continue;
406 }
407
408 esc = isEscSeq(*in);
409
410 if (!esc && pos == line_width)
411 {
412 lbuf[i++] = LINE_DELIMITER;
413 pos = 0;
414 continue;
415 }
416
417 if (!esc)
418 pos++;
419
420 // fill input data
421 lbuf[i++] = *(in++);
422 }
423
424 // padding
425 while (pos <= line_width)
426 {
427 if (i >= buf_size)
428 break;
429 if (pos < line_width)
430 lbuf[i++] = ' ';
431 else
432 lbuf[i++] = LINE_DELIMITER;
433 pos++;
434 }
435
436 // full
437 if (i >= buf_size)
438 return -1;
439
440 lbuf[i++] = '\0';
441
442 return 0;
443}
444
445static int chk_cri_sel_update(uint8_t *cri_sel_up)
446{
447 FILE *fp;
448 struct stat file_stat;
449 uint8_t pos = plat_get_fru_sel();
450 static uint8_t pre_pos = 0xff;
451
452 fp = fopen("/mnt/data/cri_sel", "r");
453 if (fp)
454 {
455 if ((stat("/mnt/data/cri_sel", &file_stat) == 0) &&
456 (file_stat.st_mtime != frame_sel.mtime || pre_pos != pos))
457 {
458 *cri_sel_up = 1;
459 }
460 else
461 {
462 *cri_sel_up = 0;
463 }
464 fclose(fp);
465 }
466 else
467 {
468 if (frame_sel.buf == NULL || frame_sel.lines != 0 || pre_pos != pos)
469 {
470 *cri_sel_up = 1;
471 }
472 else
473 {
474 *cri_sel_up = 0;
475 }
476 }
477 pre_pos = pos;
478 return 0;
479}
480
481int plat_udbg_get_frame_info(uint8_t *num)
482{
483 *num = 3;
484 return 0;
485}
486
487int plat_udbg_get_updated_frames(uint8_t *count, uint8_t *buffer)
488{
489 uint8_t cri_sel_up = 0;
490 uint8_t info_page_up = 1;
491
492 *count = 0;
493
494 // info page update
495 if (info_page_up == 1)
496 {
497 buffer[*count] = 1;
498 *count += 1;
499 }
500
501 // cri sel update
502 chk_cri_sel_update(&cri_sel_up);
503 if (cri_sel_up == 1)
504 {
505 buffer[*count] = 2;
506 *count += 1;
507 }
508
509 // cri sensor update
510 buffer[*count] = 3;
511 *count += 1;
512
513 return 0;
514}
515
516int plat_udbg_get_post_desc(uint8_t index, uint8_t *next, uint8_t phase,
517 uint8_t *end, uint8_t *length, uint8_t *buffer)
518{
Vijay Khemkacc0d6d92019-08-27 14:51:17 -0700519 nlohmann::json postObj;
520 std::string postCode;
Vijay Khemkae7d23d02019-03-08 13:13:40 -0800521
Vijay Khemkacc0d6d92019-08-27 14:51:17 -0700522 /* Get post description data stored in json file */
523 std::ifstream file(JSON_POST_DATA_FILE);
524 if (file)
525 {
526 file >> postObj;
527 file.close();
528 }
529 else
530 {
531 phosphor::logging::log<phosphor::logging::level::ERR>(
532 "Post code description file not found",
533 phosphor::logging::entry("POST_CODE_FILE=%s", JSON_POST_DATA_FILE));
534 return -1;
535 }
536
537 std::string phaseStr = "PhaseAny";
538 if (postObj.find(phaseStr) == postObj.end())
539 {
540 phaseStr = "Phase" + std::to_string(phase);
541 }
542
543 if (postObj.find(phaseStr) == postObj.end())
544 {
545 phosphor::logging::log<phosphor::logging::level::ERR>(
546 "Post code phase not available",
547 phosphor::logging::entry("PHASE=%d", phase));
548 return -1;
549 }
550
551 auto phaseObj = postObj[phaseStr];
552 int phaseSize = phaseObj.size();
553
554 for (int i = 0; i < phaseSize; i++)
555 {
556 postCode = phaseObj[i][0];
557 if (index == stoul(postCode, nullptr, 16))
558 {
559 std::string postDesc = phaseObj[i][1];
560 *length = postDesc.size();
561 memcpy(buffer, postDesc.data(), *length);
562 buffer[*length] = '\0';
563
564 if (phaseSize != i + 1)
565 {
566 postCode = phaseObj[i + 1][0];
567 *next = stoul(postCode, nullptr, 16);
568 *end = 0;
569 }
570 else
571 {
572 if (postObj.size() != phase)
573 {
574 std::string nextPhaseStr =
575 "Phase" + std::to_string(phase + 1);
576 postCode = postObj[nextPhaseStr][0][0];
577 *next = stoul(postCode, nullptr, 16);
578 *end = 0;
579 }
580 else
581 {
582 *next = 0xff;
583 *end = 1;
584 }
585 }
586
587 return 0;
588 }
589 }
590
591 phosphor::logging::log<phosphor::logging::level::ERR>(
592 "Post code description data not available",
593 phosphor::logging::entry("PHASE_CODE=%d_0x%x", phase, index));
594 return -1;
Vijay Khemkae7d23d02019-03-08 13:13:40 -0800595}
596
Vijay Khemkae7d23d02019-03-08 13:13:40 -0800597int plat_udbg_get_gpio_desc(uint8_t index, uint8_t *next, uint8_t *level,
Vijay Khemka38183d62019-08-28 16:19:33 -0700598 uint8_t *def, uint8_t *length, uint8_t *buffer)
Vijay Khemkae7d23d02019-03-08 13:13:40 -0800599{
Vijay Khemka38183d62019-08-28 16:19:33 -0700600 nlohmann::json gpioObj;
601 std::string gpioPin;
602
603 /* Get gpio data stored in json file */
604 std::ifstream file(JSON_GPIO_DATA_FILE);
605 if (file)
606 {
607 file >> gpioObj;
608 file.close();
609 }
610 else
611 {
612 phosphor::logging::log<phosphor::logging::level::ERR>(
613 "GPIO pin description file not found",
614 phosphor::logging::entry("GPIO_PIN_DETAILS_FILE=%s",
615 JSON_GPIO_DATA_FILE));
616 return -1;
617 }
618
619 if (gpioObj.find(DEBUG_GPIO_KEY) == gpioObj.end())
620 {
621 phosphor::logging::log<phosphor::logging::level::ERR>(
622 "GPIO pin details not available",
623 phosphor::logging::entry("GPIO_JSON_KEY=%d", DEBUG_GPIO_KEY));
624 return -1;
625 }
626
627 auto obj = gpioObj[DEBUG_GPIO_KEY];
628 int objSize = obj.size();
629
630 for (int i = 0; i < objSize; i++)
631 {
632 if (obj[i].size() != GPIO_ARRAY_SIZE)
633 {
634 phosphor::logging::log<phosphor::logging::level::ERR>(
635 "Size of gpio array is incorrect",
636 phosphor::logging::entry("EXPECTED_SIZE=%d", GPIO_ARRAY_SIZE));
637 return -1;
638 }
639
640 gpioPin = obj[i][GPIO_PIN_INDEX];
641 if (index == stoul(gpioPin, nullptr, 16))
642 {
643 if (objSize != i + 1)
644 {
645 gpioPin = obj[i + 1][GPIO_PIN_INDEX];
646 *next = stoul(gpioPin, nullptr, 16);
647 }
648 else
649 {
650 *next = 0xff;
651 }
652
653 *level = obj[i][GPIO_LEVEL_INDEX];
654 *def = obj[i][GPIO_DEF_INDEX];
655 std::string gpioDesc = obj[i][GPIO_DESC_INDEX];
656 *length = gpioDesc.size();
657 memcpy(buffer, gpioDesc.data(), *length);
658 buffer[*length] = '\0';
659
660 return 0;
661 }
662 }
663
664 phosphor::logging::log<phosphor::logging::level::ERR>(
665 "GPIO pin description data not available",
666 phosphor::logging::entry("GPIO_PIN=0x%x", index));
667 return -1;
Vijay Khemkae7d23d02019-03-08 13:13:40 -0800668}
669
670static int udbg_get_cri_sel(uint8_t frame, uint8_t page, uint8_t *next,
671 uint8_t *count, uint8_t *buffer)
672{
673 int len;
674 int ret;
675 char line_buff[FRAME_PAGE_BUF_SIZE], *fptr;
676 const char *ptr;
677 FILE *fp;
678 struct stat file_stat;
679 uint8_t pos = plat_get_fru_sel();
680 static uint8_t pre_pos = FRU_ALL;
681 bool pos_changed = pre_pos != pos;
682
683 pre_pos = pos;
684
685 /* Revisit this */
686 fp = fopen("/mnt/data/cri_sel", "r");
687 if (fp)
688 {
689 if ((stat("/mnt/data/cri_sel", &file_stat) == 0) &&
690 (file_stat.st_mtime != frame_sel.mtime || pos_changed))
691 {
692 // initialize and clear frame
693 frame_sel.init(FRAME_BUFF_SIZE);
694 frame_sel.overwrite = 1;
695 frame_sel.max_page = 20;
696 frame_sel.mtime = file_stat.st_mtime;
697 snprintf(frame_sel.title, 32, "Cri SEL");
698
699 while (fgets(line_buff, FRAME_PAGE_BUF_SIZE, fp))
700 {
701 // Remove newline
702 line_buff[strlen(line_buff) - 1] = '\0';
703 ptr = line_buff;
704 // Find message
705 ptr = strstr(ptr, "local0.err");
706 if (ptr == NULL)
707 {
708 continue;
709 }
710
711 if ((ptr = strrchr(ptr, ':')) == NULL)
712 {
713 continue;
714 }
715 len = strlen(ptr);
716 if (len > 2)
717 {
718 // to skip log string ": "
719 ptr += 2;
720 }
721 // Write new message
722 frame_sel.insert(ptr, 0);
723 }
724 }
725 fclose(fp);
726 }
727 else
728 {
729 // Title only
730 frame_sel.init(FRAME_BUFF_SIZE);
731 snprintf(frame_sel.title, 32, "Cri SEL");
732 frame_sel.mtime = 0;
733 }
734
735 if (page > frame_sel.pages)
736 {
737 return -1;
738 }
739
740 ret = frame_sel.getPage(page, (char *)buffer, FRAME_PAGE_BUF_SIZE);
741 if (ret < 0)
742 {
743 *count = 0;
744 return -1;
745 }
746 *count = (uint8_t)ret;
747
748 if (page < frame_sel.pages)
749 *next = page + 1;
750 else
751 *next = 0xFF; // Set the value of next to 0xFF to indicate this is the
752 // last page
753
754 return 0;
755}
756
757static int udbg_get_cri_sensor(uint8_t frame, uint8_t page, uint8_t *next,
758 uint8_t *count, uint8_t *buffer)
759{
Vijay Khemka427b2762019-12-12 12:49:25 -0800760 int ret;
761 double fvalue;
Vijay Khemkae7d23d02019-03-08 13:13:40 -0800762
763 if (page == 1)
764 {
765 // Only update frame data while getting page 1
766
767 // initialize and clear frame
768 frame_snr.init(FRAME_BUFF_SIZE);
769 snprintf(frame_snr.title, 32, "CriSensor");
Vijay Khemka427b2762019-12-12 12:49:25 -0800770
771 nlohmann::json senObj;
772
773 /* Get critical sensor names stored in json file */
774 std::ifstream file(JSON_SENSOR_NAMES_FILE);
775 if (file)
776 {
777 file >> senObj;
778 file.close();
779 }
780 else
781 {
782 phosphor::logging::log<phosphor::logging::level::ERR>(
783 "Critical Sensor names file not found",
784 phosphor::logging::entry("CRI_SENSOR_NAMES_FILE=%s",
785 JSON_SENSOR_NAMES_FILE));
786 return -1;
787 }
788
789 /* Get sensors values for all critical sensors */
790 for (auto &j : senObj.items())
791 {
792 std::string senName = j.key();
793 auto val = j.value();
794
795 if (ipmi::storage::getSensorValue(senName, fvalue) == 0)
796 {
797 std::stringstream ss;
798 ss << fvalue;
799
800 std::string senStr;
801 if (val.find("short_name") != val.end())
802 senStr = val["short_name"];
803 else
804 senStr = senName;
805
806 senStr += ss.str();
807 frame_snr.append(senStr.c_str(), 0);
808 }
809 else
810 {
811 phosphor::logging::log<phosphor::logging::level::INFO>(
812 "Critical sensor not found",
813 phosphor::logging::entry("CRI_SENSOR_NAME=%s",
814 senName.c_str()));
815 }
816 }
817
Vijay Khemkae7d23d02019-03-08 13:13:40 -0800818 } // End of update frame
819
820 if (page > frame_snr.pages)
821 {
822 return -1;
823 }
824
825 ret = frame_snr.getPage(page, (char *)buffer, FRAME_PAGE_BUF_SIZE);
826 if (ret < 0)
827 {
828 *count = 0;
829 return -1;
830 }
831 *count = (uint8_t)ret;
832
833 if (page < frame_snr.pages)
834 *next = page + 1;
835 else
836 *next = 0xFF; // Set the value of next to 0xFF to indicate this is the
837 // last page
838
839 return 0;
840}
841
Vijay Khemka88884b82019-08-27 15:23:07 -0700842static int getBiosVer(std::string &ver)
843{
844 nlohmann::json appObj;
845
846 std::ifstream file(JSON_APP_DATA_FILE);
847 if (file)
848 {
849 file >> appObj;
850 file.close();
851 if (appObj.find(KEY_SYSFW_VER) != appObj.end())
852 {
853 ver = appObj[KEY_SYSFW_VER].get<std::string>();
854 return 0;
855 }
856 }
857
858 return -1;
859}
860
Vijay Khemkae7d23d02019-03-08 13:13:40 -0800861static int udbg_get_info_page(uint8_t frame, uint8_t page, uint8_t *next,
862 uint8_t *count, uint8_t *buffer)
863{
864 char line_buff[1000], *pres_dev = line_buff;
865 uint8_t pos = plat_get_fru_sel();
866 const char *delim = "\n";
867 int ret;
868 std::string serialName = "BOARD_SERIAL_NUMBER";
869 std::string partName = "BOARD_PART_NUMBER";
870 std::string verDel = "VERSION=";
871 std::string verPath = "/etc/os-release";
872
873 if (page == 1)
874 {
875 // Only update frame data while getting page 1
876
877 // initialize and clear frame
878 frame_info.init(FRAME_BUFF_SIZE);
879 snprintf(frame_info.title, 32, "SYS_Info");
880
881 // FRU TBD:
882 std::string data;
883 frame_info.append("SN:", 0);
884 if (getFruData(data, serialName) != 0)
885 {
886 data = "Not Found";
887 }
888 frame_info.append(data.c_str(), 1);
889 frame_info.append("PN:", 0);
890 if (getFruData(data, partName) != 0)
891 {
892 data = "Not Found";
893 }
894 frame_info.append(data.c_str(), 1);
895
896 // LAN
897 getNetworkData(3, line_buff);
898 frame_info.append("BMC_IP:", 0);
899 frame_info.append(line_buff, 1);
900 getNetworkData(59, line_buff);
901 frame_info.append("BMC_IPv6:", 0);
902 frame_info.append(line_buff, 1);
903
904 // BMC ver
905 std::ifstream file(verPath);
906 if (file)
907 {
908 std::string line;
909 while (std::getline(file, line))
910 {
911 if (line.find(verDel) != std::string::npos)
912 {
913 std::string bmcVer = line.substr(verDel.size());
914 frame_info.append("BMC_FW_ver:", 0);
915 frame_info.append(bmcVer.c_str(), 1);
916 break;
917 }
918 }
919 }
920
Vijay Khemkae7d23d02019-03-08 13:13:40 -0800921 // BIOS ver
Vijay Khemka88884b82019-08-27 15:23:07 -0700922 std::string biosVer;
923 if (getBiosVer(biosVer) == 0)
924 {
925 frame_info.append("BIOS_FW_ver:", 0);
926 frame_info.append(biosVer.c_str(), 1);
927 }
Vijay Khemkae7d23d02019-03-08 13:13:40 -0800928
Vijay Khemka88884b82019-08-27 15:23:07 -0700929 /* TBD: ME status and Board ID needs implementation */
Vijay Khemkae7d23d02019-03-08 13:13:40 -0800930 // ME status
931
932 // Board ID
933
934 // Battery - Use Escape sequence
935 frame_info.append("Battery:", 0);
936 frame_info.append(ESC_BAT " ", 1);
937 // frame_info.append(&frame_info, esc_bat, 1);
938
939 // MCU Version - Use Escape sequence
940 frame_info.append("MCUbl_ver:", 0);
941 frame_info.append(ESC_MCU_BL_VER, 1);
942 frame_info.append("MCU_ver:", 0);
943 frame_info.append(ESC_MCU_RUN_VER, 1);
944
945 // TBD:
946 // Sys config present device
947
948 } // End of update frame
949
950 if (page > frame_info.pages)
951 {
952 return -1;
953 }
954
955 ret = frame_info.getPage(page, (char *)buffer, FRAME_PAGE_BUF_SIZE);
956 if (ret < 0)
957 {
958 *count = 0;
959 return -1;
960 }
961 *count = (uint8_t)ret;
962
963 if (page < frame_info.pages)
964 *next = page + 1;
965 else
966 *next = 0xFF; // Set the value of next to 0xFF to indicate this is the
967 // last page
968
969 return 0;
970}
971
972int plat_udbg_get_frame_data(uint8_t frame, uint8_t page, uint8_t *next,
973 uint8_t *count, uint8_t *buffer)
974{
975 switch (frame)
976 {
977 case 1: // info_page
978 return udbg_get_info_page(frame, page, next, count, buffer);
979 case 2: // critical SEL
980 return udbg_get_cri_sel(frame, page, next, count, buffer);
981 case 3: // critical Sensor
982 return udbg_get_cri_sensor(frame, page, next, count, buffer);
983 default:
984 return -1;
985 }
986}
987
988static uint8_t panel_main(uint8_t item)
989{
990 // Update item list when select item 0
991 switch (item)
992 {
993 case 1:
994 return panels[PANEL_BOOT_ORDER].select(0);
995 case 2:
996 return panels[PANEL_POWER_POLICY].select(0);
997 default:
998 return PANEL_MAIN;
999 }
1000}
1001
1002static uint8_t panel_boot_order(uint8_t item)
1003{
1004 int i;
1005 unsigned char buff[MAX_VALUE_LEN], pickup, len;
1006 uint8_t pos = plat_get_fru_sel();
1007
1008 /* To be implemented */
1009 /*
1010 if (pos != FRU_ALL && pal_get_boot_order(pos, buff, buff, &len) == 0)
1011 {
1012 if (item > 0 && item < SIZE_BOOT_ORDER)
1013 {
1014 pickup = buff[item];
1015 while (item > 1)
1016 {
1017 buff[item] = buff[item -1];
1018 item--;
1019 }
1020 buff[item] = pickup;
1021 buff[0] |= 0x80;
1022 pal_set_boot_order(pos, buff, buff, &len);
1023
1024 // refresh items
1025 return panels[PANEL_BOOT_ORDER].select(0);
1026 }
1027
1028 // '*': boot flags valid, BIOS has not yet read
1029 snprintf(panels[PANEL_BOOT_ORDER].item_str[0], 32,
1030 "Boot Order%c", (buff[0] & 0x80)?'*':'\0');
1031
1032 for (i = 1; i < SIZE_BOOT_ORDER; i++)
1033 {
1034 switch (buff[i])
1035 {
1036 case 0x0:
1037 snprintf(panels[PANEL_BOOT_ORDER].item_str[i], 32,
1038 " USB device");
1039 break;
1040 case 0x1:
1041 snprintf(panels[PANEL_BOOT_ORDER].item_str[i], 32,
1042 " Network v4");
1043 break;
1044 case (0x1 | 0x8):
1045 snprintf(panels[PANEL_BOOT_ORDER].item_str[i], 32,
1046 " Network v6");
1047 break;
1048 case 0x2:
1049 snprintf(panels[PANEL_BOOT_ORDER].item_str[i], 32,
1050 " SATA HDD");
1051 break;
1052 case 0x3:
1053 snprintf(panels[PANEL_BOOT_ORDER].item_str[i], 32,
1054 " SATA-CDROM");
1055 break;
1056 case 0x4:
1057 snprintf(panels[PANEL_BOOT_ORDER].item_str[i], 32,
1058 " Other");
1059 break;
1060 default:
1061 panels[PANEL_BOOT_ORDER].item_str[i][0] = '\0';
1062 break;
1063 }
1064 }
1065
1066 // remove empty items
1067 for (i--; (strlen(panels[PANEL_BOOT_ORDER].item_str[i]) == 0) && (i > 0); i--)
1068 ;
1069
1070 panels[PANEL_BOOT_ORDER].item_num = i;
1071 } else
1072 {
1073 panels[PANEL_BOOT_ORDER].item_num = 0;
1074 }
1075 */
1076 return PANEL_BOOT_ORDER;
1077}
1078
1079static uint8_t panel_power_policy(uint8_t item)
1080{
1081 uint8_t buff[32] = {0};
1082 uint8_t res_len;
1083 uint8_t pos = plat_get_fru_sel();
1084 uint8_t policy;
1085 // uint8_t pwr_policy_item_map[3] = {POWER_CFG_ON, POWER_CFG_LPS,
1086 // POWER_CFG_OFF};
1087
1088 /* To be cleaned */
1089 /*
1090 if (pos != FRU_ALL) {
1091 if (item > 0 && item <= sizeof(pwr_policy_item_map)) {
1092 policy = pwr_policy_item_map[item - 1];
1093 pal_set_power_restore_policy(pos, &policy, NULL);
1094 }
1095 pal_get_chassis_status(pos, NULL, buff, &res_len);
1096 policy = (((uint8_t)buff[0]) >> 5) & 0x7;
1097 snprintf(panels[PANEL_POWER_POLICY].item_str[1], 32,
1098 "%cPower On", policy == POWER_CFG_ON ? '*' : ' ');
1099 snprintf(panels[PANEL_POWER_POLICY].item_str[2], 32,
1100 "%cLast State", policy == POWER_CFG_LPS ? '*' : ' ');
1101 snprintf(panels[PANEL_POWER_POLICY].item_str[3], 32,
1102 "%cPower Off", policy == POWER_CFG_OFF ? '*' : ' ');
1103 panels[PANEL_POWER_POLICY].item_num = 3;
1104 } else {
1105 panels[PANEL_POWER_POLICY].item_num = 0;
1106 }
1107 */
1108 return PANEL_POWER_POLICY;
1109}
1110
1111int plat_udbg_control_panel(uint8_t panel, uint8_t operation, uint8_t item,
1112 uint8_t *count, uint8_t *buffer)
1113{
1114 if (panel > panelNum || panel < PANEL_MAIN)
1115 return IPMI_CC_PARM_OUT_OF_RANGE;
1116
1117 // No more item; End of item list
1118 if (item > panels[panel].item_num)
1119 return IPMI_CC_PARM_OUT_OF_RANGE;
1120
1121 switch (operation)
1122 {
1123 case 0: // Get Description
1124 break;
1125 case 1: // Select item
1126 panel = panels[panel].select(item);
1127 item = 0;
1128 break;
1129 case 2: // Back
1130 panel = panels[panel].parent;
1131 item = 0;
1132 break;
1133 default:
1134 return IPMI_CC_PARM_OUT_OF_RANGE;
1135 }
1136
1137 buffer[0] = panel;
1138 buffer[1] = item;
1139 buffer[2] = strlen(panels[panel].item_str[item]);
1140 if (buffer[2] > 0 && (buffer[2] + 3) < FRAME_PAGE_BUF_SIZE)
1141 {
1142 memcpy(&buffer[3], panels[panel].item_str[item], buffer[2]);
1143 }
1144 *count = buffer[2] + 3;
1145 return IPMI_CC_OK;
1146}
1147
1148} // end of namespace ipmi