blob: 59dc5669e62ec58caa89fb9c583efb18fa23824b [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 Khemkaf43fad42019-12-26 11:47:58 -0800800 int prec = 0; // Default value
801
802 if (val.find("precision") != val.end())
803 prec = val["precision"];
804
805 ss << std::fixed << std::setprecision(prec) << fvalue;
Vijay Khemka427b2762019-12-12 12:49:25 -0800806
807 std::string senStr;
808 if (val.find("short_name") != val.end())
809 senStr = val["short_name"];
810 else
811 senStr = senName;
812
813 senStr += ss.str();
Vijay Khemka58bd5d82019-12-13 11:05:56 -0800814
815 /* Get unit string for sensor and append in output */
816 std::string unitStr;
817 if (ipmi::storage::getSensorUnit(senName, unitStr) == 0)
818 senStr += unitStr;
819
Vijay Khemka427b2762019-12-12 12:49:25 -0800820 frame_snr.append(senStr.c_str(), 0);
821 }
822 else
823 {
824 phosphor::logging::log<phosphor::logging::level::INFO>(
825 "Critical sensor not found",
826 phosphor::logging::entry("CRI_SENSOR_NAME=%s",
827 senName.c_str()));
828 }
829 }
830
Vijay Khemkae7d23d02019-03-08 13:13:40 -0800831 } // End of update frame
832
833 if (page > frame_snr.pages)
834 {
835 return -1;
836 }
837
838 ret = frame_snr.getPage(page, (char *)buffer, FRAME_PAGE_BUF_SIZE);
839 if (ret < 0)
840 {
841 *count = 0;
842 return -1;
843 }
844 *count = (uint8_t)ret;
845
846 if (page < frame_snr.pages)
847 *next = page + 1;
848 else
849 *next = 0xFF; // Set the value of next to 0xFF to indicate this is the
850 // last page
851
852 return 0;
853}
854
Vijay Khemka88884b82019-08-27 15:23:07 -0700855static int getBiosVer(std::string &ver)
856{
857 nlohmann::json appObj;
858
859 std::ifstream file(JSON_APP_DATA_FILE);
860 if (file)
861 {
862 file >> appObj;
863 file.close();
864 if (appObj.find(KEY_SYSFW_VER) != appObj.end())
865 {
866 ver = appObj[KEY_SYSFW_VER].get<std::string>();
867 return 0;
868 }
869 }
870
871 return -1;
872}
873
Vijay Khemkae7d23d02019-03-08 13:13:40 -0800874static int udbg_get_info_page(uint8_t frame, uint8_t page, uint8_t *next,
875 uint8_t *count, uint8_t *buffer)
876{
877 char line_buff[1000], *pres_dev = line_buff;
878 uint8_t pos = plat_get_fru_sel();
879 const char *delim = "\n";
880 int ret;
881 std::string serialName = "BOARD_SERIAL_NUMBER";
882 std::string partName = "BOARD_PART_NUMBER";
883 std::string verDel = "VERSION=";
884 std::string verPath = "/etc/os-release";
885
886 if (page == 1)
887 {
888 // Only update frame data while getting page 1
889
890 // initialize and clear frame
891 frame_info.init(FRAME_BUFF_SIZE);
892 snprintf(frame_info.title, 32, "SYS_Info");
893
894 // FRU TBD:
895 std::string data;
896 frame_info.append("SN:", 0);
897 if (getFruData(data, serialName) != 0)
898 {
899 data = "Not Found";
900 }
901 frame_info.append(data.c_str(), 1);
902 frame_info.append("PN:", 0);
903 if (getFruData(data, partName) != 0)
904 {
905 data = "Not Found";
906 }
907 frame_info.append(data.c_str(), 1);
908
909 // LAN
910 getNetworkData(3, line_buff);
911 frame_info.append("BMC_IP:", 0);
912 frame_info.append(line_buff, 1);
913 getNetworkData(59, line_buff);
914 frame_info.append("BMC_IPv6:", 0);
915 frame_info.append(line_buff, 1);
916
917 // BMC ver
918 std::ifstream file(verPath);
919 if (file)
920 {
921 std::string line;
922 while (std::getline(file, line))
923 {
924 if (line.find(verDel) != std::string::npos)
925 {
926 std::string bmcVer = line.substr(verDel.size());
927 frame_info.append("BMC_FW_ver:", 0);
928 frame_info.append(bmcVer.c_str(), 1);
929 break;
930 }
931 }
932 }
933
Vijay Khemkae7d23d02019-03-08 13:13:40 -0800934 // BIOS ver
Vijay Khemka88884b82019-08-27 15:23:07 -0700935 std::string biosVer;
936 if (getBiosVer(biosVer) == 0)
937 {
938 frame_info.append("BIOS_FW_ver:", 0);
939 frame_info.append(biosVer.c_str(), 1);
940 }
Vijay Khemkae7d23d02019-03-08 13:13:40 -0800941
Vijay Khemka88884b82019-08-27 15:23:07 -0700942 /* TBD: ME status and Board ID needs implementation */
Vijay Khemkae7d23d02019-03-08 13:13:40 -0800943 // ME status
944
945 // Board ID
946
947 // Battery - Use Escape sequence
948 frame_info.append("Battery:", 0);
949 frame_info.append(ESC_BAT " ", 1);
950 // frame_info.append(&frame_info, esc_bat, 1);
951
952 // MCU Version - Use Escape sequence
953 frame_info.append("MCUbl_ver:", 0);
954 frame_info.append(ESC_MCU_BL_VER, 1);
955 frame_info.append("MCU_ver:", 0);
956 frame_info.append(ESC_MCU_RUN_VER, 1);
957
958 // TBD:
959 // Sys config present device
960
961 } // End of update frame
962
963 if (page > frame_info.pages)
964 {
965 return -1;
966 }
967
968 ret = frame_info.getPage(page, (char *)buffer, FRAME_PAGE_BUF_SIZE);
969 if (ret < 0)
970 {
971 *count = 0;
972 return -1;
973 }
974 *count = (uint8_t)ret;
975
976 if (page < frame_info.pages)
977 *next = page + 1;
978 else
979 *next = 0xFF; // Set the value of next to 0xFF to indicate this is the
980 // last page
981
982 return 0;
983}
984
985int plat_udbg_get_frame_data(uint8_t frame, uint8_t page, uint8_t *next,
986 uint8_t *count, uint8_t *buffer)
987{
988 switch (frame)
989 {
990 case 1: // info_page
991 return udbg_get_info_page(frame, page, next, count, buffer);
992 case 2: // critical SEL
993 return udbg_get_cri_sel(frame, page, next, count, buffer);
994 case 3: // critical Sensor
995 return udbg_get_cri_sensor(frame, page, next, count, buffer);
996 default:
997 return -1;
998 }
999}
1000
1001static uint8_t panel_main(uint8_t item)
1002{
1003 // Update item list when select item 0
1004 switch (item)
1005 {
1006 case 1:
1007 return panels[PANEL_BOOT_ORDER].select(0);
1008 case 2:
1009 return panels[PANEL_POWER_POLICY].select(0);
1010 default:
1011 return PANEL_MAIN;
1012 }
1013}
1014
1015static uint8_t panel_boot_order(uint8_t item)
1016{
1017 int i;
1018 unsigned char buff[MAX_VALUE_LEN], pickup, len;
1019 uint8_t pos = plat_get_fru_sel();
1020
1021 /* To be implemented */
1022 /*
1023 if (pos != FRU_ALL && pal_get_boot_order(pos, buff, buff, &len) == 0)
1024 {
1025 if (item > 0 && item < SIZE_BOOT_ORDER)
1026 {
1027 pickup = buff[item];
1028 while (item > 1)
1029 {
1030 buff[item] = buff[item -1];
1031 item--;
1032 }
1033 buff[item] = pickup;
1034 buff[0] |= 0x80;
1035 pal_set_boot_order(pos, buff, buff, &len);
1036
1037 // refresh items
1038 return panels[PANEL_BOOT_ORDER].select(0);
1039 }
1040
1041 // '*': boot flags valid, BIOS has not yet read
1042 snprintf(panels[PANEL_BOOT_ORDER].item_str[0], 32,
1043 "Boot Order%c", (buff[0] & 0x80)?'*':'\0');
1044
1045 for (i = 1; i < SIZE_BOOT_ORDER; i++)
1046 {
1047 switch (buff[i])
1048 {
1049 case 0x0:
1050 snprintf(panels[PANEL_BOOT_ORDER].item_str[i], 32,
1051 " USB device");
1052 break;
1053 case 0x1:
1054 snprintf(panels[PANEL_BOOT_ORDER].item_str[i], 32,
1055 " Network v4");
1056 break;
1057 case (0x1 | 0x8):
1058 snprintf(panels[PANEL_BOOT_ORDER].item_str[i], 32,
1059 " Network v6");
1060 break;
1061 case 0x2:
1062 snprintf(panels[PANEL_BOOT_ORDER].item_str[i], 32,
1063 " SATA HDD");
1064 break;
1065 case 0x3:
1066 snprintf(panels[PANEL_BOOT_ORDER].item_str[i], 32,
1067 " SATA-CDROM");
1068 break;
1069 case 0x4:
1070 snprintf(panels[PANEL_BOOT_ORDER].item_str[i], 32,
1071 " Other");
1072 break;
1073 default:
1074 panels[PANEL_BOOT_ORDER].item_str[i][0] = '\0';
1075 break;
1076 }
1077 }
1078
1079 // remove empty items
1080 for (i--; (strlen(panels[PANEL_BOOT_ORDER].item_str[i]) == 0) && (i > 0); i--)
1081 ;
1082
1083 panels[PANEL_BOOT_ORDER].item_num = i;
1084 } else
1085 {
1086 panels[PANEL_BOOT_ORDER].item_num = 0;
1087 }
1088 */
1089 return PANEL_BOOT_ORDER;
1090}
1091
1092static uint8_t panel_power_policy(uint8_t item)
1093{
1094 uint8_t buff[32] = {0};
1095 uint8_t res_len;
1096 uint8_t pos = plat_get_fru_sel();
1097 uint8_t policy;
1098 // uint8_t pwr_policy_item_map[3] = {POWER_CFG_ON, POWER_CFG_LPS,
1099 // POWER_CFG_OFF};
1100
1101 /* To be cleaned */
1102 /*
1103 if (pos != FRU_ALL) {
1104 if (item > 0 && item <= sizeof(pwr_policy_item_map)) {
1105 policy = pwr_policy_item_map[item - 1];
1106 pal_set_power_restore_policy(pos, &policy, NULL);
1107 }
1108 pal_get_chassis_status(pos, NULL, buff, &res_len);
1109 policy = (((uint8_t)buff[0]) >> 5) & 0x7;
1110 snprintf(panels[PANEL_POWER_POLICY].item_str[1], 32,
1111 "%cPower On", policy == POWER_CFG_ON ? '*' : ' ');
1112 snprintf(panels[PANEL_POWER_POLICY].item_str[2], 32,
1113 "%cLast State", policy == POWER_CFG_LPS ? '*' : ' ');
1114 snprintf(panels[PANEL_POWER_POLICY].item_str[3], 32,
1115 "%cPower Off", policy == POWER_CFG_OFF ? '*' : ' ');
1116 panels[PANEL_POWER_POLICY].item_num = 3;
1117 } else {
1118 panels[PANEL_POWER_POLICY].item_num = 0;
1119 }
1120 */
1121 return PANEL_POWER_POLICY;
1122}
1123
1124int plat_udbg_control_panel(uint8_t panel, uint8_t operation, uint8_t item,
1125 uint8_t *count, uint8_t *buffer)
1126{
1127 if (panel > panelNum || panel < PANEL_MAIN)
1128 return IPMI_CC_PARM_OUT_OF_RANGE;
1129
1130 // No more item; End of item list
1131 if (item > panels[panel].item_num)
1132 return IPMI_CC_PARM_OUT_OF_RANGE;
1133
1134 switch (operation)
1135 {
1136 case 0: // Get Description
1137 break;
1138 case 1: // Select item
1139 panel = panels[panel].select(item);
1140 item = 0;
1141 break;
1142 case 2: // Back
1143 panel = panels[panel].parent;
1144 item = 0;
1145 break;
1146 default:
1147 return IPMI_CC_PARM_OUT_OF_RANGE;
1148 }
1149
1150 buffer[0] = panel;
1151 buffer[1] = item;
1152 buffer[2] = strlen(panels[panel].item_str[item]);
1153 if (buffer[2] > 0 && (buffer[2] + 3) < FRAME_PAGE_BUF_SIZE)
1154 {
1155 memcpy(&buffer[3], panels[panel].item_str[item], buffer[2]);
1156 }
1157 *count = buffer[2] + 3;
1158 return IPMI_CC_OK;
1159}
1160
1161} // end of namespace ipmi