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