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