blob: 7d5f74e61869d249e282bb41f2afa95d3656c1fa [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>
18#include <stdbool.h>
19#include <stdio.h>
20#include <sys/stat.h>
21
Vijay Khemka63c99be2020-05-27 19:14:35 -070022#include <appcommands.hpp>
23#include <ipmid/api.hpp>
24#include <nlohmann/json.hpp>
Vijay Khemkacc0d6d92019-08-27 14:51:17 -070025#include <phosphor-logging/log.hpp>
Vijay Khemka317999d2020-01-02 13:43:42 -080026#include <sdbusplus/asio/connection.hpp>
Vijay Khemka63c99be2020-05-27 19:14:35 -070027
28#include <fstream>
29#include <iomanip>
30#include <iostream>
31#include <sstream>
Vijay Khemkae7d23d02019-03-08 13:13:40 -080032
33namespace ipmi
34{
35
Vijay Khemka11b33a02019-12-13 12:04:20 -080036#define JSON_POST_DATA_FILE "/usr/share/lcd-debug/post_desc.json"
37#define JSON_GPIO_DATA_FILE "/usr/share/lcd-debug/gpio_desc.json"
Vijay Khemka427b2762019-12-12 12:49:25 -080038#define JSON_SENSOR_NAMES_FILE "/usr/share/lcd-debug/cri_sensors.json"
Vijay Khemka11b33a02019-12-13 12:04:20 -080039
Vijay Khemkae7d23d02019-03-08 13:13:40 -080040#define ETH_INTF_NAME "eth0"
41
42#define ESCAPE "\x1B"
43#define ESC_BAT ESCAPE "B"
44#define ESC_MCU_BL_VER ESCAPE "U"
45#define ESC_MCU_RUN_VER ESCAPE "R"
46#define ESC_ALT ESCAPE "[5;7m"
47#define ESC_RST ESCAPE "[m"
48
49#define LINE_DELIMITER '\x1F'
50
51#define FRAME_BUFF_SIZE 4096
52#define FRAME_PAGE_BUF_SIZE 256
53#define FRU_ALL 0
54#define MAX_VALUE_LEN 64
55
Vijay Khemka38183d62019-08-28 16:19:33 -070056#define DEBUG_GPIO_KEY "GpioDesc"
57#define GPIO_ARRAY_SIZE 4
58#define GPIO_PIN_INDEX 0
59#define GPIO_LEVEL_INDEX 1
60#define GPIO_DEF_INDEX 2
61#define GPIO_DESC_INDEX 3
62
Vijay Khemkae7d23d02019-03-08 13:13:40 -080063/* Used for systems which do not specifically have a
64 * phase, and we want to ignore the phase provided by the
65 * debug card */
66#define PHASE_ANY 0xff
67
Vijay Khemka63c99be2020-05-27 19:14:35 -070068ipmi_ret_t getNetworkData(uint8_t lan_param, char* data);
69int8_t getFruData(std::string& serial, std::string& name);
Vijay Khemkae7d23d02019-03-08 13:13:40 -080070
Vijay Khemka427b2762019-12-12 12:49:25 -080071/* Declare storage functions used here */
72namespace storage
73{
Vijay Khemka63c99be2020-05-27 19:14:35 -070074int getSensorValue(std::string&, double&);
75int getSensorUnit(std::string&, std::string&);
Vijay Khemka58bd5d82019-12-13 11:05:56 -080076} // namespace storage
Vijay Khemka427b2762019-12-12 12:49:25 -080077
Vijay Khemka317999d2020-01-02 13:43:42 -080078static constexpr bool DEBUG = false;
79static const uint8_t meAddress = 1;
80static constexpr uint8_t lun = 0;
81
82using IpmbMethodType =
83 std::tuple<int, uint8_t, uint8_t, uint8_t, uint8_t, std::vector<uint8_t>>;
84
Vijay Khemkae7d23d02019-03-08 13:13:40 -080085typedef struct _sensor_desc
86{
87 char name[16];
88 uint8_t sensor_num;
89 char unit[5];
90 uint8_t fru;
91 uint8_t disp_prec;
92} sensor_desc_t;
93
94struct frame
95{
96 char title[32];
97 size_t max_size;
98 size_t max_page;
Vijay Khemka63c99be2020-05-27 19:14:35 -070099 char* buf;
Vijay Khemkae7d23d02019-03-08 13:13:40 -0800100 uint16_t idx_head, idx_tail;
101 uint8_t line_per_page;
102 uint8_t line_width;
103 uint16_t lines, pages;
104 uint8_t esc_sts;
105 uint8_t overwrite;
106 time_t mtime;
107 frame() : buf(NULL), pages(0), mtime(0)
108 {
109 }
110 int init(size_t size);
Vijay Khemka63c99be2020-05-27 19:14:35 -0700111 int append(const char* string, int indent);
112 int insert(const char* string, int indent);
113 int getPage(int page, char* page_buf, size_t page_buf_size);
Vijay Khemkae7d23d02019-03-08 13:13:40 -0800114 int isFull();
115 int isEscSeq(char chr);
Vijay Khemka63c99be2020-05-27 19:14:35 -0700116 int parse(char* buf, size_t buf_size, const char* input, int indent);
Vijay Khemkae7d23d02019-03-08 13:13:40 -0800117};
118
119struct frame frame_info;
120struct frame frame_sel;
121struct frame frame_snr;
122
123enum ENUM_PANEL
124{
125 PANEL_MAIN = 1,
126 PANEL_BOOT_ORDER = 2,
127 PANEL_POWER_POLICY = 3,
128};
129
130struct ctrl_panel
131{
132 uint8_t parent;
133 uint8_t item_num;
134 char item_str[8][32];
135 uint8_t (*select)(uint8_t item);
136};
137
138static uint8_t panel_main(uint8_t item);
139static uint8_t panel_boot_order(uint8_t item);
140static uint8_t panel_power_policy(uint8_t item);
141
142static struct ctrl_panel panels[] = {
143 {/* dummy entry for making other to 1-based */},
144 {
145 .parent = PANEL_MAIN,
146 .item_num = 2,
147 .item_str =
148 {
149 "User Setting",
150 ">Boot Order",
151 ">Power Policy",
152 },
153 .select = panel_main,
154 },
155 {
156 .parent = PANEL_MAIN,
157 .item_num = 0,
158 .item_str =
159 {
160 "Boot Order",
161 },
162 .select = panel_boot_order,
163 },
164 {
165 .parent = PANEL_MAIN,
166 .item_num = 0,
167 .item_str =
168 {
169 "Power Policy",
170 },
171 .select = panel_power_policy,
172 },
173};
174
175static int panelNum = (sizeof(panels) / sizeof(struct ctrl_panel)) - 1;
176
177/* Returns the FRU the hand-switch is switched to. If it is switched to BMC
178 * it returns FRU_ALL. Note, if in err, it returns FRU_ALL */
179static uint8_t plat_get_fru_sel()
180{
181 // For Tiogapass it just return 1, can modify to support more platform
182 return 1;
183}
184
185// return 0 on seccuess
186int frame::init(size_t size)
187{
188 // Reset status
189 idx_head = idx_tail = 0;
190 lines = 0;
191 esc_sts = 0;
192 pages = 1;
193
194 if (buf != NULL && max_size == size)
195 {
196 // reinit
197 return 0;
198 }
199
200 if (buf != NULL && max_size != size)
201 {
202 delete[] buf;
203 }
204 // Initialize Configuration
205 title[0] = '\0';
206 buf = new char[size];
207 max_size = size;
208 max_page = size;
209 line_per_page = 7;
210 line_width = 16;
211 overwrite = 0;
212
213 if (buf)
214 return 0;
215 else
216 return -1;
217}
218
219// return 0 on seccuess
Vijay Khemka63c99be2020-05-27 19:14:35 -0700220int frame::append(const char* string, int indent)
Vijay Khemkae7d23d02019-03-08 13:13:40 -0800221{
222 const size_t buf_size = 64;
223 char lbuf[buf_size];
Vijay Khemka63c99be2020-05-27 19:14:35 -0700224 char* ptr;
Vijay Khemkae7d23d02019-03-08 13:13:40 -0800225 int ret;
226
227 ret = parse(lbuf, buf_size, string, indent);
228
229 if (ret < 0)
230 return ret;
231
232 int len = strlen(string);
233 for (ptr = lbuf; *ptr != '\0'; ptr++)
234 {
235 if (isFull())
236 {
237 if (overwrite)
238 {
239 if (buf[idx_head] == LINE_DELIMITER)
240 lines--;
241 idx_head = (idx_head + 1) % max_size;
242 }
243 else
244 return -1;
245 }
246
247 buf[idx_tail] = *ptr;
248 if (*ptr == LINE_DELIMITER)
249 lines++;
250
251 idx_tail = (idx_tail + 1) % max_size;
252 }
253
254 pages = (lines / line_per_page) + ((lines % line_per_page) ? 1 : 0);
255
256 if (pages > max_page)
257 pages = max_page;
258
259 return 0;
260}
261
262// return 0 on seccuess
Vijay Khemka63c99be2020-05-27 19:14:35 -0700263int frame::insert(const char* string, int indent)
Vijay Khemkae7d23d02019-03-08 13:13:40 -0800264{
265 const size_t buf_size = 128;
266 char lbuf[buf_size];
Vijay Khemka63c99be2020-05-27 19:14:35 -0700267 char* ptr;
Vijay Khemkae7d23d02019-03-08 13:13:40 -0800268 int ret;
269 int i;
270
271 ret = parse(lbuf, buf_size, string, indent);
272
273 if (ret < 0)
274 return ret;
275
276 for (i = strlen(lbuf) - 1; i >= 0; i--)
277 {
278 ptr = &lbuf[i];
279 if (isFull())
280 {
281 if (overwrite)
282 {
283 idx_tail = (idx_tail + max_size - 1) % max_size;
284 if (buf[idx_tail] == LINE_DELIMITER)
285 lines--;
286 }
287 else
288 return -1;
289 }
290
291 idx_head = (idx_head + max_size - 1) % max_size;
292
293 buf[idx_head] = *ptr;
294 if (*ptr == LINE_DELIMITER)
295 lines++;
296 }
297
298 pages = (lines / line_per_page) + ((lines % line_per_page) ? 1 : 0);
299
300 if (pages > max_page)
301 pages = max_page;
302
303 return 0;
304}
305
306// return page size
Vijay Khemka63c99be2020-05-27 19:14:35 -0700307int frame::getPage(int page, char* page_buf, size_t page_buf_size)
Vijay Khemkae7d23d02019-03-08 13:13:40 -0800308{
309 int ret;
310 uint16_t line = 0;
311 uint16_t idx, len;
312
313 if (buf == NULL)
314 return -1;
315
316 // 1-based page
317 if (page > pages || page < 1)
318 return -1;
319
320 if (page_buf == NULL || page_buf_size < 0)
321 return -1;
322
323 ret = snprintf(page_buf, 17, "%-10s %02d/%02d", title, page, pages);
324 len = strlen(page_buf);
325 if (ret < 0)
326 return -1;
327
328 line = 0;
329 idx = idx_head;
330 while (line < ((page - 1) * line_per_page) && idx != idx_tail)
331 {
332 if (buf[idx] == LINE_DELIMITER)
333 line++;
334 idx = (idx + 1) % max_size;
335 }
336
337 while (line < ((page)*line_per_page) && idx != idx_tail)
338 {
339 if (buf[idx] == LINE_DELIMITER)
340 {
341 line++;
342 }
343 else
344 {
345 page_buf[len++] = buf[idx];
346 if (len == (page_buf_size - 1))
347 {
348 break;
349 }
350 }
351 idx = (idx + 1) % max_size;
352 }
353
354 return len;
355}
356
357// return 1 for frame buffer full
358int frame::isFull()
359{
360 if (buf == NULL)
361 return -1;
362
363 if ((idx_tail + 1) % max_size == idx_head)
364 return 1;
365 else
366 return 0;
367}
368
369// return 1 for Escape Sequence
370int frame::isEscSeq(char chr)
371{
372 uint8_t curr_sts = esc_sts;
373
374 if (esc_sts == 0 && (chr == 0x1b))
375 esc_sts = 1; // Escape Sequence
376 else if (esc_sts == 1 && (chr == 0x5b))
377 esc_sts = 2; // Control Sequence Introducer(CSI)
378 else if (esc_sts == 1 && (chr != 0x5b))
379 esc_sts = 0;
380 else if (esc_sts == 2 && (chr >= 0x40 && chr <= 0x7e))
381 esc_sts = 0;
382
383 if (curr_sts || esc_sts)
384 return 1;
385 else
386 return 0;
387}
388
389// return 0 on success
Vijay Khemka63c99be2020-05-27 19:14:35 -0700390int frame::parse(char* lbuf, size_t buf_size, const char* input, int indent)
Vijay Khemkae7d23d02019-03-08 13:13:40 -0800391{
392 uint8_t pos, esc;
393 int i;
394 const char *in, *end;
395
396 if (buf == NULL || input == NULL)
397 return -1;
398
399 if (indent >= line_width || indent < 0)
400 return -1;
401
402 in = input;
403 end = in + strlen(input);
404 pos = 0; // line position
405 esc = 0; // escape state
406 i = 0; // buf index
407 while (in != end)
408 {
409 if (i >= buf_size)
410 break;
411
412 if (pos < indent)
413 {
414 // fill indent
415 lbuf[i++] = ' ';
416 pos++;
417 continue;
418 }
419
420 esc = isEscSeq(*in);
421
422 if (!esc && pos == line_width)
423 {
424 lbuf[i++] = LINE_DELIMITER;
425 pos = 0;
426 continue;
427 }
428
429 if (!esc)
430 pos++;
431
432 // fill input data
433 lbuf[i++] = *(in++);
434 }
435
436 // padding
437 while (pos <= line_width)
438 {
439 if (i >= buf_size)
440 break;
441 if (pos < line_width)
442 lbuf[i++] = ' ';
443 else
444 lbuf[i++] = LINE_DELIMITER;
445 pos++;
446 }
447
448 // full
449 if (i >= buf_size)
450 return -1;
451
452 lbuf[i++] = '\0';
453
454 return 0;
455}
456
Vijay Khemka63c99be2020-05-27 19:14:35 -0700457static int chk_cri_sel_update(uint8_t* cri_sel_up)
Vijay Khemkae7d23d02019-03-08 13:13:40 -0800458{
Vijay Khemka63c99be2020-05-27 19:14:35 -0700459 FILE* fp;
Vijay Khemkae7d23d02019-03-08 13:13:40 -0800460 struct stat file_stat;
461 uint8_t pos = plat_get_fru_sel();
462 static uint8_t pre_pos = 0xff;
463
464 fp = fopen("/mnt/data/cri_sel", "r");
465 if (fp)
466 {
467 if ((stat("/mnt/data/cri_sel", &file_stat) == 0) &&
468 (file_stat.st_mtime != frame_sel.mtime || pre_pos != pos))
469 {
470 *cri_sel_up = 1;
471 }
472 else
473 {
474 *cri_sel_up = 0;
475 }
476 fclose(fp);
477 }
478 else
479 {
480 if (frame_sel.buf == NULL || frame_sel.lines != 0 || pre_pos != pos)
481 {
482 *cri_sel_up = 1;
483 }
484 else
485 {
486 *cri_sel_up = 0;
487 }
488 }
489 pre_pos = pos;
490 return 0;
491}
492
Vijay Khemka63c99be2020-05-27 19:14:35 -0700493int plat_udbg_get_frame_info(uint8_t* num)
Vijay Khemkae7d23d02019-03-08 13:13:40 -0800494{
495 *num = 3;
496 return 0;
497}
498
Vijay Khemka63c99be2020-05-27 19:14:35 -0700499int plat_udbg_get_updated_frames(uint8_t* count, uint8_t* buffer)
Vijay Khemkae7d23d02019-03-08 13:13:40 -0800500{
501 uint8_t cri_sel_up = 0;
502 uint8_t info_page_up = 1;
503
504 *count = 0;
505
506 // info page update
507 if (info_page_up == 1)
508 {
509 buffer[*count] = 1;
510 *count += 1;
511 }
512
513 // cri sel update
514 chk_cri_sel_update(&cri_sel_up);
515 if (cri_sel_up == 1)
516 {
517 buffer[*count] = 2;
518 *count += 1;
519 }
520
521 // cri sensor update
522 buffer[*count] = 3;
523 *count += 1;
524
525 return 0;
526}
527
Vijay Khemka63c99be2020-05-27 19:14:35 -0700528int plat_udbg_get_post_desc(uint8_t index, uint8_t* next, uint8_t phase,
529 uint8_t* end, uint8_t* length, uint8_t* buffer)
Vijay Khemkae7d23d02019-03-08 13:13:40 -0800530{
Vijay Khemkacc0d6d92019-08-27 14:51:17 -0700531 nlohmann::json postObj;
532 std::string postCode;
Vijay Khemkae7d23d02019-03-08 13:13:40 -0800533
Vijay Khemkacc0d6d92019-08-27 14:51:17 -0700534 /* Get post description data stored in json file */
535 std::ifstream file(JSON_POST_DATA_FILE);
536 if (file)
537 {
538 file >> postObj;
539 file.close();
540 }
541 else
542 {
543 phosphor::logging::log<phosphor::logging::level::ERR>(
544 "Post code description file not found",
545 phosphor::logging::entry("POST_CODE_FILE=%s", JSON_POST_DATA_FILE));
546 return -1;
547 }
548
549 std::string phaseStr = "PhaseAny";
550 if (postObj.find(phaseStr) == postObj.end())
551 {
552 phaseStr = "Phase" + std::to_string(phase);
553 }
554
555 if (postObj.find(phaseStr) == postObj.end())
556 {
557 phosphor::logging::log<phosphor::logging::level::ERR>(
558 "Post code phase not available",
559 phosphor::logging::entry("PHASE=%d", phase));
560 return -1;
561 }
562
563 auto phaseObj = postObj[phaseStr];
564 int phaseSize = phaseObj.size();
565
566 for (int i = 0; i < phaseSize; i++)
567 {
568 postCode = phaseObj[i][0];
569 if (index == stoul(postCode, nullptr, 16))
570 {
571 std::string postDesc = phaseObj[i][1];
572 *length = postDesc.size();
573 memcpy(buffer, postDesc.data(), *length);
574 buffer[*length] = '\0';
575
576 if (phaseSize != i + 1)
577 {
578 postCode = phaseObj[i + 1][0];
579 *next = stoul(postCode, nullptr, 16);
580 *end = 0;
581 }
582 else
583 {
584 if (postObj.size() != phase)
585 {
586 std::string nextPhaseStr =
587 "Phase" + std::to_string(phase + 1);
588 postCode = postObj[nextPhaseStr][0][0];
589 *next = stoul(postCode, nullptr, 16);
590 *end = 0;
591 }
592 else
593 {
594 *next = 0xff;
595 *end = 1;
596 }
597 }
598
599 return 0;
600 }
601 }
602
603 phosphor::logging::log<phosphor::logging::level::ERR>(
604 "Post code description data not available",
605 phosphor::logging::entry("PHASE_CODE=%d_0x%x", phase, index));
606 return -1;
Vijay Khemkae7d23d02019-03-08 13:13:40 -0800607}
608
Vijay Khemka63c99be2020-05-27 19:14:35 -0700609int plat_udbg_get_gpio_desc(uint8_t index, uint8_t* next, uint8_t* level,
610 uint8_t* def, uint8_t* length, uint8_t* buffer)
Vijay Khemkae7d23d02019-03-08 13:13:40 -0800611{
Vijay Khemka38183d62019-08-28 16:19:33 -0700612 nlohmann::json gpioObj;
613 std::string gpioPin;
614
615 /* Get gpio data stored in json file */
616 std::ifstream file(JSON_GPIO_DATA_FILE);
617 if (file)
618 {
619 file >> gpioObj;
620 file.close();
621 }
622 else
623 {
624 phosphor::logging::log<phosphor::logging::level::ERR>(
625 "GPIO pin description file not found",
626 phosphor::logging::entry("GPIO_PIN_DETAILS_FILE=%s",
627 JSON_GPIO_DATA_FILE));
628 return -1;
629 }
630
631 if (gpioObj.find(DEBUG_GPIO_KEY) == gpioObj.end())
632 {
633 phosphor::logging::log<phosphor::logging::level::ERR>(
634 "GPIO pin details not available",
635 phosphor::logging::entry("GPIO_JSON_KEY=%d", DEBUG_GPIO_KEY));
636 return -1;
637 }
638
639 auto obj = gpioObj[DEBUG_GPIO_KEY];
640 int objSize = obj.size();
641
642 for (int i = 0; i < objSize; i++)
643 {
644 if (obj[i].size() != GPIO_ARRAY_SIZE)
645 {
646 phosphor::logging::log<phosphor::logging::level::ERR>(
647 "Size of gpio array is incorrect",
648 phosphor::logging::entry("EXPECTED_SIZE=%d", GPIO_ARRAY_SIZE));
649 return -1;
650 }
651
652 gpioPin = obj[i][GPIO_PIN_INDEX];
653 if (index == stoul(gpioPin, nullptr, 16))
654 {
655 if (objSize != i + 1)
656 {
657 gpioPin = obj[i + 1][GPIO_PIN_INDEX];
658 *next = stoul(gpioPin, nullptr, 16);
659 }
660 else
661 {
662 *next = 0xff;
663 }
664
665 *level = obj[i][GPIO_LEVEL_INDEX];
666 *def = obj[i][GPIO_DEF_INDEX];
667 std::string gpioDesc = obj[i][GPIO_DESC_INDEX];
668 *length = gpioDesc.size();
669 memcpy(buffer, gpioDesc.data(), *length);
670 buffer[*length] = '\0';
671
672 return 0;
673 }
674 }
675
676 phosphor::logging::log<phosphor::logging::level::ERR>(
677 "GPIO pin description data not available",
678 phosphor::logging::entry("GPIO_PIN=0x%x", index));
679 return -1;
Vijay Khemkae7d23d02019-03-08 13:13:40 -0800680}
681
Vijay Khemka63c99be2020-05-27 19:14:35 -0700682static int udbg_get_cri_sel(uint8_t frame, uint8_t page, uint8_t* next,
683 uint8_t* count, uint8_t* buffer)
Vijay Khemkae7d23d02019-03-08 13:13:40 -0800684{
685 int len;
686 int ret;
687 char line_buff[FRAME_PAGE_BUF_SIZE], *fptr;
Vijay Khemka63c99be2020-05-27 19:14:35 -0700688 const char* ptr;
689 FILE* fp;
Vijay Khemkae7d23d02019-03-08 13:13:40 -0800690 struct stat file_stat;
691 uint8_t pos = plat_get_fru_sel();
692 static uint8_t pre_pos = FRU_ALL;
693 bool pos_changed = pre_pos != pos;
694
695 pre_pos = pos;
696
697 /* Revisit this */
698 fp = fopen("/mnt/data/cri_sel", "r");
699 if (fp)
700 {
701 if ((stat("/mnt/data/cri_sel", &file_stat) == 0) &&
702 (file_stat.st_mtime != frame_sel.mtime || pos_changed))
703 {
704 // initialize and clear frame
705 frame_sel.init(FRAME_BUFF_SIZE);
706 frame_sel.overwrite = 1;
707 frame_sel.max_page = 20;
708 frame_sel.mtime = file_stat.st_mtime;
709 snprintf(frame_sel.title, 32, "Cri SEL");
710
711 while (fgets(line_buff, FRAME_PAGE_BUF_SIZE, fp))
712 {
713 // Remove newline
714 line_buff[strlen(line_buff) - 1] = '\0';
715 ptr = line_buff;
716 // Find message
717 ptr = strstr(ptr, "local0.err");
718 if (ptr == NULL)
719 {
720 continue;
721 }
722
723 if ((ptr = strrchr(ptr, ':')) == NULL)
724 {
725 continue;
726 }
727 len = strlen(ptr);
728 if (len > 2)
729 {
730 // to skip log string ": "
731 ptr += 2;
732 }
733 // Write new message
734 frame_sel.insert(ptr, 0);
735 }
736 }
737 fclose(fp);
738 }
739 else
740 {
741 // Title only
742 frame_sel.init(FRAME_BUFF_SIZE);
743 snprintf(frame_sel.title, 32, "Cri SEL");
744 frame_sel.mtime = 0;
745 }
746
747 if (page > frame_sel.pages)
748 {
749 return -1;
750 }
751
Vijay Khemka63c99be2020-05-27 19:14:35 -0700752 ret = frame_sel.getPage(page, (char*)buffer, FRAME_PAGE_BUF_SIZE);
Vijay Khemkae7d23d02019-03-08 13:13:40 -0800753 if (ret < 0)
754 {
755 *count = 0;
756 return -1;
757 }
758 *count = (uint8_t)ret;
759
760 if (page < frame_sel.pages)
761 *next = page + 1;
762 else
763 *next = 0xFF; // Set the value of next to 0xFF to indicate this is the
764 // last page
765
766 return 0;
767}
768
Vijay Khemka63c99be2020-05-27 19:14:35 -0700769static int udbg_get_cri_sensor(uint8_t frame, uint8_t page, uint8_t* next,
770 uint8_t* count, uint8_t* buffer)
Vijay Khemkae7d23d02019-03-08 13:13:40 -0800771{
Vijay Khemka427b2762019-12-12 12:49:25 -0800772 int ret;
773 double fvalue;
Vijay Khemkae7d23d02019-03-08 13:13:40 -0800774
775 if (page == 1)
776 {
777 // Only update frame data while getting page 1
778
779 // initialize and clear frame
780 frame_snr.init(FRAME_BUFF_SIZE);
781 snprintf(frame_snr.title, 32, "CriSensor");
Vijay Khemka427b2762019-12-12 12:49:25 -0800782
783 nlohmann::json senObj;
784
785 /* Get critical sensor names stored in json file */
786 std::ifstream file(JSON_SENSOR_NAMES_FILE);
787 if (file)
788 {
789 file >> senObj;
790 file.close();
791 }
792 else
793 {
794 phosphor::logging::log<phosphor::logging::level::ERR>(
795 "Critical Sensor names file not found",
796 phosphor::logging::entry("CRI_SENSOR_NAMES_FILE=%s",
797 JSON_SENSOR_NAMES_FILE));
798 return -1;
799 }
800
801 /* Get sensors values for all critical sensors */
Vijay Khemka63c99be2020-05-27 19:14:35 -0700802 for (auto& j : senObj.items())
Vijay Khemka427b2762019-12-12 12:49:25 -0800803 {
804 std::string senName = j.key();
805 auto val = j.value();
806
807 if (ipmi::storage::getSensorValue(senName, fvalue) == 0)
808 {
809 std::stringstream ss;
Vijay Khemkaf43fad42019-12-26 11:47:58 -0800810 int prec = 0; // Default value
811
812 if (val.find("precision") != val.end())
813 prec = val["precision"];
814
815 ss << std::fixed << std::setprecision(prec) << fvalue;
Vijay Khemka427b2762019-12-12 12:49:25 -0800816
817 std::string senStr;
818 if (val.find("short_name") != val.end())
819 senStr = val["short_name"];
820 else
821 senStr = senName;
822
823 senStr += ss.str();
Vijay Khemka58bd5d82019-12-13 11:05:56 -0800824
825 /* Get unit string for sensor and append in output */
826 std::string unitStr;
827 if (ipmi::storage::getSensorUnit(senName, unitStr) == 0)
828 senStr += unitStr;
829
Vijay Khemka427b2762019-12-12 12:49:25 -0800830 frame_snr.append(senStr.c_str(), 0);
831 }
832 else
833 {
834 phosphor::logging::log<phosphor::logging::level::INFO>(
835 "Critical sensor not found",
836 phosphor::logging::entry("CRI_SENSOR_NAME=%s",
837 senName.c_str()));
838 }
839 }
840
Vijay Khemkae7d23d02019-03-08 13:13:40 -0800841 } // End of update frame
842
843 if (page > frame_snr.pages)
844 {
845 return -1;
846 }
847
Vijay Khemka63c99be2020-05-27 19:14:35 -0700848 ret = frame_snr.getPage(page, (char*)buffer, FRAME_PAGE_BUF_SIZE);
Vijay Khemkae7d23d02019-03-08 13:13:40 -0800849 if (ret < 0)
850 {
851 *count = 0;
852 return -1;
853 }
854 *count = (uint8_t)ret;
855
856 if (page < frame_snr.pages)
857 *next = page + 1;
858 else
859 *next = 0xFF; // Set the value of next to 0xFF to indicate this is the
860 // last page
861
862 return 0;
863}
864
Vijay Khemka63c99be2020-05-27 19:14:35 -0700865static int getBiosVer(std::string& ver)
Vijay Khemka88884b82019-08-27 15:23:07 -0700866{
867 nlohmann::json appObj;
868
869 std::ifstream file(JSON_APP_DATA_FILE);
870 if (file)
871 {
872 file >> appObj;
873 file.close();
874 if (appObj.find(KEY_SYSFW_VER) != appObj.end())
875 {
876 ver = appObj[KEY_SYSFW_VER].get<std::string>();
877 return 0;
878 }
879 }
880
881 return -1;
882}
883
Vijay Khemka63c99be2020-05-27 19:14:35 -0700884int sendMeCmd(uint8_t netFn, uint8_t cmd, std::vector<uint8_t>& cmdData,
885 std::vector<uint8_t>& respData)
Vijay Khemkadd14c0f2020-03-18 14:48:13 -0700886{
887 auto bus = getSdBus();
888
889 if (DEBUG)
890 {
891 std::cout << "ME NetFn:cmd " << (int)netFn << ":" << (int)cmd << "\n";
892 std::cout << "ME req data: ";
893 for (auto d : cmdData)
894 {
895 std::cout << d << " ";
896 }
897 std::cout << "\n";
898 }
899
900 auto method = bus->new_method_call("xyz.openbmc_project.Ipmi.Channel.Ipmb",
901 "/xyz/openbmc_project/Ipmi/Channel/Ipmb",
902 "org.openbmc.Ipmb", "sendRequest");
903 method.append(meAddress, netFn, lun, cmd, cmdData);
904
905 auto reply = bus->call(method);
906 if (reply.is_method_error())
907 {
908 phosphor::logging::log<phosphor::logging::level::ERR>(
909 "Error reading from ME");
910 return -1;
911 }
912
913 IpmbMethodType resp;
914 reply.read(resp);
915
916 respData =
917 std::move(std::get<std::remove_reference_t<decltype(respData)>>(resp));
918
919 if (DEBUG)
920 {
921 std::cout << "ME resp data: ";
922 for (auto d : respData)
923 {
924 std::cout << d << " ";
925 }
926 std::cout << "\n";
927 }
928
929 return 0;
930}
931
Vijay Khemka63c99be2020-05-27 19:14:35 -0700932static int getMeStatus(std::string& status)
Vijay Khemka317999d2020-01-02 13:43:42 -0800933{
934 uint8_t cmd = 0x01; // Get Device id command
935 uint8_t netFn = 0x06; // Netfn for APP
936 std::shared_ptr<sdbusplus::asio::connection> bus = getSdBus();
937 std::vector<uint8_t> cmdData;
938
939 auto method = bus->new_method_call("xyz.openbmc_project.Ipmi.Channel.Ipmb",
940 "/xyz/openbmc_project/Ipmi/Channel/Ipmb",
941 "org.openbmc.Ipmb", "sendRequest");
942 method.append(meAddress, netFn, lun, cmd, cmdData);
943
944 auto reply = bus->call(method);
945 if (reply.is_method_error())
946 {
947 std::cerr << "Error reading from ME\n";
948 return -1;
949 }
950
951 IpmbMethodType resp;
952 reply.read(resp);
953
954 std::vector<uint8_t> data;
955 data = std::get<5>(resp);
956
957 if (DEBUG)
958 {
959 std::cout << "ME Get ID: ";
960 for (size_t d : data)
961 {
962 std::cout << d << " ";
963 }
964 std::cout << "\n";
965 }
966
967 if (data[2] & 0x80)
968 status = "recovery mode";
969 else
970 status = "operation mode";
971
972 return 0;
973}
974
Vijay Khemka63c99be2020-05-27 19:14:35 -0700975static int udbg_get_info_page(uint8_t frame, uint8_t page, uint8_t* next,
976 uint8_t* count, uint8_t* buffer)
Vijay Khemkae7d23d02019-03-08 13:13:40 -0800977{
978 char line_buff[1000], *pres_dev = line_buff;
979 uint8_t pos = plat_get_fru_sel();
Vijay Khemka63c99be2020-05-27 19:14:35 -0700980 const char* delim = "\n";
Vijay Khemkae7d23d02019-03-08 13:13:40 -0800981 int ret;
982 std::string serialName = "BOARD_SERIAL_NUMBER";
983 std::string partName = "BOARD_PART_NUMBER";
984 std::string verDel = "VERSION=";
985 std::string verPath = "/etc/os-release";
986
987 if (page == 1)
988 {
989 // Only update frame data while getting page 1
990
991 // initialize and clear frame
992 frame_info.init(FRAME_BUFF_SIZE);
993 snprintf(frame_info.title, 32, "SYS_Info");
994
995 // FRU TBD:
996 std::string data;
997 frame_info.append("SN:", 0);
998 if (getFruData(data, serialName) != 0)
999 {
1000 data = "Not Found";
1001 }
1002 frame_info.append(data.c_str(), 1);
1003 frame_info.append("PN:", 0);
1004 if (getFruData(data, partName) != 0)
1005 {
1006 data = "Not Found";
1007 }
1008 frame_info.append(data.c_str(), 1);
1009
1010 // LAN
1011 getNetworkData(3, line_buff);
1012 frame_info.append("BMC_IP:", 0);
1013 frame_info.append(line_buff, 1);
1014 getNetworkData(59, line_buff);
1015 frame_info.append("BMC_IPv6:", 0);
1016 frame_info.append(line_buff, 1);
1017
1018 // BMC ver
1019 std::ifstream file(verPath);
1020 if (file)
1021 {
1022 std::string line;
1023 while (std::getline(file, line))
1024 {
1025 if (line.find(verDel) != std::string::npos)
1026 {
1027 std::string bmcVer = line.substr(verDel.size());
1028 frame_info.append("BMC_FW_ver:", 0);
1029 frame_info.append(bmcVer.c_str(), 1);
1030 break;
1031 }
1032 }
1033 }
1034
Vijay Khemkae7d23d02019-03-08 13:13:40 -08001035 // BIOS ver
Vijay Khemka88884b82019-08-27 15:23:07 -07001036 std::string biosVer;
1037 if (getBiosVer(biosVer) == 0)
1038 {
1039 frame_info.append("BIOS_FW_ver:", 0);
1040 frame_info.append(biosVer.c_str(), 1);
1041 }
Vijay Khemkae7d23d02019-03-08 13:13:40 -08001042
Vijay Khemkae7d23d02019-03-08 13:13:40 -08001043 // ME status
Vijay Khemka317999d2020-01-02 13:43:42 -08001044 std::string meStatus;
1045 if (getMeStatus(meStatus) != 0)
1046 {
1047 phosphor::logging::log<phosphor::logging::level::WARNING>(
1048 "Reading ME status failed");
1049 meStatus = "unknown";
1050 }
1051 frame_info.append("ME_status:", 0);
1052 frame_info.append(meStatus.c_str(), 1);
Vijay Khemkae7d23d02019-03-08 13:13:40 -08001053
Vijay Khemka317999d2020-01-02 13:43:42 -08001054 /* TBD: Board ID needs implementation */
Vijay Khemkae7d23d02019-03-08 13:13:40 -08001055 // Board ID
1056
1057 // Battery - Use Escape sequence
1058 frame_info.append("Battery:", 0);
1059 frame_info.append(ESC_BAT " ", 1);
1060 // frame_info.append(&frame_info, esc_bat, 1);
1061
1062 // MCU Version - Use Escape sequence
1063 frame_info.append("MCUbl_ver:", 0);
1064 frame_info.append(ESC_MCU_BL_VER, 1);
1065 frame_info.append("MCU_ver:", 0);
1066 frame_info.append(ESC_MCU_RUN_VER, 1);
1067
1068 // TBD:
1069 // Sys config present device
1070
1071 } // End of update frame
1072
1073 if (page > frame_info.pages)
1074 {
1075 return -1;
1076 }
1077
Vijay Khemka63c99be2020-05-27 19:14:35 -07001078 ret = frame_info.getPage(page, (char*)buffer, FRAME_PAGE_BUF_SIZE);
Vijay Khemkae7d23d02019-03-08 13:13:40 -08001079 if (ret < 0)
1080 {
1081 *count = 0;
1082 return -1;
1083 }
1084 *count = (uint8_t)ret;
1085
1086 if (page < frame_info.pages)
1087 *next = page + 1;
1088 else
1089 *next = 0xFF; // Set the value of next to 0xFF to indicate this is the
1090 // last page
1091
1092 return 0;
1093}
1094
Vijay Khemka63c99be2020-05-27 19:14:35 -07001095int plat_udbg_get_frame_data(uint8_t frame, uint8_t page, uint8_t* next,
1096 uint8_t* count, uint8_t* buffer)
Vijay Khemkae7d23d02019-03-08 13:13:40 -08001097{
1098 switch (frame)
1099 {
1100 case 1: // info_page
1101 return udbg_get_info_page(frame, page, next, count, buffer);
1102 case 2: // critical SEL
1103 return udbg_get_cri_sel(frame, page, next, count, buffer);
1104 case 3: // critical Sensor
1105 return udbg_get_cri_sensor(frame, page, next, count, buffer);
1106 default:
1107 return -1;
1108 }
1109}
1110
1111static uint8_t panel_main(uint8_t item)
1112{
1113 // Update item list when select item 0
1114 switch (item)
1115 {
1116 case 1:
1117 return panels[PANEL_BOOT_ORDER].select(0);
1118 case 2:
1119 return panels[PANEL_POWER_POLICY].select(0);
1120 default:
1121 return PANEL_MAIN;
1122 }
1123}
1124
1125static uint8_t panel_boot_order(uint8_t item)
1126{
1127 int i;
1128 unsigned char buff[MAX_VALUE_LEN], pickup, len;
1129 uint8_t pos = plat_get_fru_sel();
1130
1131 /* To be implemented */
1132 /*
1133 if (pos != FRU_ALL && pal_get_boot_order(pos, buff, buff, &len) == 0)
1134 {
1135 if (item > 0 && item < SIZE_BOOT_ORDER)
1136 {
1137 pickup = buff[item];
1138 while (item > 1)
1139 {
1140 buff[item] = buff[item -1];
1141 item--;
1142 }
1143 buff[item] = pickup;
1144 buff[0] |= 0x80;
1145 pal_set_boot_order(pos, buff, buff, &len);
1146
1147 // refresh items
1148 return panels[PANEL_BOOT_ORDER].select(0);
1149 }
1150
1151 // '*': boot flags valid, BIOS has not yet read
1152 snprintf(panels[PANEL_BOOT_ORDER].item_str[0], 32,
1153 "Boot Order%c", (buff[0] & 0x80)?'*':'\0');
1154
1155 for (i = 1; i < SIZE_BOOT_ORDER; i++)
1156 {
1157 switch (buff[i])
1158 {
1159 case 0x0:
1160 snprintf(panels[PANEL_BOOT_ORDER].item_str[i], 32,
1161 " USB device");
1162 break;
1163 case 0x1:
1164 snprintf(panels[PANEL_BOOT_ORDER].item_str[i], 32,
1165 " Network v4");
1166 break;
1167 case (0x1 | 0x8):
1168 snprintf(panels[PANEL_BOOT_ORDER].item_str[i], 32,
1169 " Network v6");
1170 break;
1171 case 0x2:
1172 snprintf(panels[PANEL_BOOT_ORDER].item_str[i], 32,
1173 " SATA HDD");
1174 break;
1175 case 0x3:
1176 snprintf(panels[PANEL_BOOT_ORDER].item_str[i], 32,
1177 " SATA-CDROM");
1178 break;
1179 case 0x4:
1180 snprintf(panels[PANEL_BOOT_ORDER].item_str[i], 32,
1181 " Other");
1182 break;
1183 default:
1184 panels[PANEL_BOOT_ORDER].item_str[i][0] = '\0';
1185 break;
1186 }
1187 }
1188
1189 // remove empty items
1190 for (i--; (strlen(panels[PANEL_BOOT_ORDER].item_str[i]) == 0) && (i > 0); i--)
1191 ;
1192
1193 panels[PANEL_BOOT_ORDER].item_num = i;
1194 } else
1195 {
1196 panels[PANEL_BOOT_ORDER].item_num = 0;
1197 }
1198 */
1199 return PANEL_BOOT_ORDER;
1200}
1201
1202static uint8_t panel_power_policy(uint8_t item)
1203{
1204 uint8_t buff[32] = {0};
1205 uint8_t res_len;
1206 uint8_t pos = plat_get_fru_sel();
1207 uint8_t policy;
1208 // uint8_t pwr_policy_item_map[3] = {POWER_CFG_ON, POWER_CFG_LPS,
1209 // POWER_CFG_OFF};
1210
1211 /* To be cleaned */
1212 /*
1213 if (pos != FRU_ALL) {
1214 if (item > 0 && item <= sizeof(pwr_policy_item_map)) {
1215 policy = pwr_policy_item_map[item - 1];
1216 pal_set_power_restore_policy(pos, &policy, NULL);
1217 }
1218 pal_get_chassis_status(pos, NULL, buff, &res_len);
1219 policy = (((uint8_t)buff[0]) >> 5) & 0x7;
1220 snprintf(panels[PANEL_POWER_POLICY].item_str[1], 32,
1221 "%cPower On", policy == POWER_CFG_ON ? '*' : ' ');
1222 snprintf(panels[PANEL_POWER_POLICY].item_str[2], 32,
1223 "%cLast State", policy == POWER_CFG_LPS ? '*' : ' ');
1224 snprintf(panels[PANEL_POWER_POLICY].item_str[3], 32,
1225 "%cPower Off", policy == POWER_CFG_OFF ? '*' : ' ');
1226 panels[PANEL_POWER_POLICY].item_num = 3;
1227 } else {
1228 panels[PANEL_POWER_POLICY].item_num = 0;
1229 }
1230 */
1231 return PANEL_POWER_POLICY;
1232}
1233
1234int plat_udbg_control_panel(uint8_t panel, uint8_t operation, uint8_t item,
Vijay Khemka63c99be2020-05-27 19:14:35 -07001235 uint8_t* count, uint8_t* buffer)
Vijay Khemkae7d23d02019-03-08 13:13:40 -08001236{
1237 if (panel > panelNum || panel < PANEL_MAIN)
1238 return IPMI_CC_PARM_OUT_OF_RANGE;
1239
1240 // No more item; End of item list
1241 if (item > panels[panel].item_num)
1242 return IPMI_CC_PARM_OUT_OF_RANGE;
1243
1244 switch (operation)
1245 {
1246 case 0: // Get Description
1247 break;
1248 case 1: // Select item
1249 panel = panels[panel].select(item);
1250 item = 0;
1251 break;
1252 case 2: // Back
1253 panel = panels[panel].parent;
1254 item = 0;
1255 break;
1256 default:
1257 return IPMI_CC_PARM_OUT_OF_RANGE;
1258 }
1259
1260 buffer[0] = panel;
1261 buffer[1] = item;
1262 buffer[2] = strlen(panels[panel].item_str[item]);
1263 if (buffer[2] > 0 && (buffer[2] + 3) < FRAME_PAGE_BUF_SIZE)
1264 {
1265 memcpy(&buffer[3], panels[panel].item_str[item], buffer[2]);
1266 }
1267 *count = buffer[2] + 3;
1268 return IPMI_CC_OK;
1269}
1270
1271} // end of namespace ipmi