blob: 19adbe85b282eb6d73b2dd6f36cb25d4b885a266 [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
Karthikeyan Pasupathi813f2932022-04-06 14:10:48 +053017#include <usb-dbg.hpp>
Jayashree Dhanapal4ec80562022-06-28 15:41:47 +053018#include <commandutils.hpp>
Vijay Khemkae7d23d02019-03-08 13:13:40 -080019
20namespace ipmi
21{
22
Vijay Khemka63c99be2020-05-27 19:14:35 -070023ipmi_ret_t getNetworkData(uint8_t lan_param, char* data);
24int8_t getFruData(std::string& serial, std::string& name);
Karthikeyan Pasupathi10ff3d82022-04-06 16:27:25 +053025int8_t sysConfig(std::vector<std::string>& data, size_t pos);
Karthikeyan Pasupathid532fec2022-07-14 14:43:42 +053026int8_t procInfo(std::string& result, size_t pos);
Vijay Khemkae7d23d02019-03-08 13:13:40 -080027
Karthikeyan Pasupathi39836ff2022-01-17 12:20:06 +053028bool isMultiHostPlatform();
29
30/* Declare Host Selector interface and path */
31namespace selector
32{
33const std::string path = "/xyz/openbmc_project/Chassis/Buttons/HostSelector";
34const std::string interface =
Potin Laicff150e2022-09-19 09:34:57 +080035 "xyz.openbmc_project.Chassis.Buttons.HostSelector";
Karthikeyan Pasupathi39836ff2022-01-17 12:20:06 +053036const std::string propertyName = "Position";
37} // namespace selector
38
Vijay Khemka427b2762019-12-12 12:49:25 -080039/* Declare storage functions used here */
40namespace storage
41{
Vijay Khemka63c99be2020-05-27 19:14:35 -070042int getSensorValue(std::string&, double&);
43int getSensorUnit(std::string&, std::string&);
Vijay Khemka58bd5d82019-12-13 11:05:56 -080044} // namespace storage
Vijay Khemka427b2762019-12-12 12:49:25 -080045
Potin Laif24c78e2022-10-27 17:13:14 +080046size_t getMaxHostPosition()
47{
48 try
49 {
50 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
51 std::string service =
52 getService(*dbus, ipmi::selector::interface, ipmi::selector::path);
53 Value variant =
54 getDbusProperty(*dbus, service, ipmi::selector::path,
55 ipmi::selector::interface, "MaxPosition");
56 size_t result = std::get<size_t>(variant);
57 return result;
58 }
59 catch (...)
60 {
61 phosphor::logging::log<phosphor::logging::level::ERR>(
62 "Failed to get MaxPosition from DBus");
63 }
64
65 return MAX_HOST_POS;
66}
67
Karthikeyan Pasupathi39836ff2022-01-17 12:20:06 +053068size_t getSelectorPosition()
69{
70 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
71 std::string service =
72 getService(*dbus, ipmi::selector::interface, ipmi::selector::path);
73 Value variant = getDbusProperty(*dbus, service, ipmi::selector::path,
74 ipmi::selector::interface,
75 ipmi::selector::propertyName);
76 size_t result = std::get<size_t>(variant);
77 return result;
78}
79
Vijay Khemkae7d23d02019-03-08 13:13:40 -080080static int panelNum = (sizeof(panels) / sizeof(struct ctrl_panel)) - 1;
81
82/* Returns the FRU the hand-switch is switched to. If it is switched to BMC
83 * it returns FRU_ALL. Note, if in err, it returns FRU_ALL */
Karthikeyan Pasupathi39836ff2022-01-17 12:20:06 +053084static size_t plat_get_fru_sel()
Vijay Khemkae7d23d02019-03-08 13:13:40 -080085{
Karthikeyan Pasupathi39836ff2022-01-17 12:20:06 +053086 size_t position;
87 bool platform = isMultiHostPlatform();
88
89 if (platform == true)
90 {
91 try
92 {
93 size_t hostPosition = getSelectorPosition();
94 position = hostPosition;
95 if (position == BMC_POSITION)
96 {
97 return FRU_ALL;
98 }
99 }
100 catch (...)
101 {
102 std::cout << "Error reading host selector position" << std::endl;
103 }
104 }
105 else
106 {
107 // For Tiogapass it just return 1, can modify to support more platform
108 position = 1;
109 }
110 return position;
Vijay Khemkae7d23d02019-03-08 13:13:40 -0800111}
112
113// return 0 on seccuess
114int frame::init(size_t size)
115{
116 // Reset status
117 idx_head = idx_tail = 0;
118 lines = 0;
119 esc_sts = 0;
120 pages = 1;
121
122 if (buf != NULL && max_size == size)
123 {
124 // reinit
125 return 0;
126 }
127
128 if (buf != NULL && max_size != size)
129 {
130 delete[] buf;
131 }
132 // Initialize Configuration
133 title[0] = '\0';
134 buf = new char[size];
135 max_size = size;
136 max_page = size;
137 line_per_page = 7;
138 line_width = 16;
139 overwrite = 0;
140
141 if (buf)
142 return 0;
143 else
144 return -1;
145}
146
147// return 0 on seccuess
Vijay Khemka63c99be2020-05-27 19:14:35 -0700148int frame::append(const char* string, int indent)
Vijay Khemkae7d23d02019-03-08 13:13:40 -0800149{
Karthikeyan Pasupathi10ff3d82022-04-06 16:27:25 +0530150 const size_t buf_size = 128;
Vijay Khemkae7d23d02019-03-08 13:13:40 -0800151 char lbuf[buf_size];
Vijay Khemka63c99be2020-05-27 19:14:35 -0700152 char* ptr;
Vijay Khemkae7d23d02019-03-08 13:13:40 -0800153 int ret;
154
155 ret = parse(lbuf, buf_size, string, indent);
156
157 if (ret < 0)
158 return ret;
159
Vijay Khemkae7d23d02019-03-08 13:13:40 -0800160 for (ptr = lbuf; *ptr != '\0'; ptr++)
161 {
162 if (isFull())
163 {
164 if (overwrite)
165 {
166 if (buf[idx_head] == LINE_DELIMITER)
167 lines--;
168 idx_head = (idx_head + 1) % max_size;
169 }
170 else
171 return -1;
172 }
173
174 buf[idx_tail] = *ptr;
175 if (*ptr == LINE_DELIMITER)
176 lines++;
177
178 idx_tail = (idx_tail + 1) % max_size;
179 }
180
181 pages = (lines / line_per_page) + ((lines % line_per_page) ? 1 : 0);
182
183 if (pages > max_page)
184 pages = max_page;
185
186 return 0;
187}
188
189// return 0 on seccuess
Vijay Khemka63c99be2020-05-27 19:14:35 -0700190int frame::insert(const char* string, int indent)
Vijay Khemkae7d23d02019-03-08 13:13:40 -0800191{
192 const size_t buf_size = 128;
193 char lbuf[buf_size];
Vijay Khemka63c99be2020-05-27 19:14:35 -0700194 char* ptr;
Vijay Khemkae7d23d02019-03-08 13:13:40 -0800195 int ret;
196 int i;
197
198 ret = parse(lbuf, buf_size, string, indent);
199
200 if (ret < 0)
201 return ret;
202
203 for (i = strlen(lbuf) - 1; i >= 0; i--)
204 {
205 ptr = &lbuf[i];
206 if (isFull())
207 {
208 if (overwrite)
209 {
210 idx_tail = (idx_tail + max_size - 1) % max_size;
211 if (buf[idx_tail] == LINE_DELIMITER)
212 lines--;
213 }
214 else
215 return -1;
216 }
217
218 idx_head = (idx_head + max_size - 1) % max_size;
219
220 buf[idx_head] = *ptr;
221 if (*ptr == LINE_DELIMITER)
222 lines++;
223 }
224
225 pages = (lines / line_per_page) + ((lines % line_per_page) ? 1 : 0);
226
227 if (pages > max_page)
228 pages = max_page;
229
230 return 0;
231}
232
233// return page size
Vijay Khemka63c99be2020-05-27 19:14:35 -0700234int frame::getPage(int page, char* page_buf, size_t page_buf_size)
Vijay Khemkae7d23d02019-03-08 13:13:40 -0800235{
236 int ret;
237 uint16_t line = 0;
238 uint16_t idx, len;
239
240 if (buf == NULL)
241 return -1;
242
243 // 1-based page
244 if (page > pages || page < 1)
245 return -1;
246
Willy Tue39f9392022-06-15 13:24:20 -0700247 if (page_buf == NULL || page_buf_size == 0)
Vijay Khemkae7d23d02019-03-08 13:13:40 -0800248 return -1;
249
250 ret = snprintf(page_buf, 17, "%-10s %02d/%02d", title, page, pages);
251 len = strlen(page_buf);
252 if (ret < 0)
253 return -1;
254
255 line = 0;
256 idx = idx_head;
257 while (line < ((page - 1) * line_per_page) && idx != idx_tail)
258 {
259 if (buf[idx] == LINE_DELIMITER)
260 line++;
261 idx = (idx + 1) % max_size;
262 }
263
264 while (line < ((page)*line_per_page) && idx != idx_tail)
265 {
266 if (buf[idx] == LINE_DELIMITER)
267 {
268 line++;
269 }
270 else
271 {
272 page_buf[len++] = buf[idx];
273 if (len == (page_buf_size - 1))
274 {
275 break;
276 }
277 }
278 idx = (idx + 1) % max_size;
279 }
280
281 return len;
282}
283
284// return 1 for frame buffer full
285int frame::isFull()
286{
287 if (buf == NULL)
288 return -1;
289
290 if ((idx_tail + 1) % max_size == idx_head)
291 return 1;
292 else
293 return 0;
294}
295
296// return 1 for Escape Sequence
297int frame::isEscSeq(char chr)
298{
299 uint8_t curr_sts = esc_sts;
300
301 if (esc_sts == 0 && (chr == 0x1b))
302 esc_sts = 1; // Escape Sequence
303 else if (esc_sts == 1 && (chr == 0x5b))
304 esc_sts = 2; // Control Sequence Introducer(CSI)
305 else if (esc_sts == 1 && (chr != 0x5b))
306 esc_sts = 0;
307 else if (esc_sts == 2 && (chr >= 0x40 && chr <= 0x7e))
308 esc_sts = 0;
309
310 if (curr_sts || esc_sts)
311 return 1;
312 else
313 return 0;
314}
315
316// return 0 on success
Vijay Khemka63c99be2020-05-27 19:14:35 -0700317int frame::parse(char* lbuf, size_t buf_size, const char* input, int indent)
Vijay Khemkae7d23d02019-03-08 13:13:40 -0800318{
319 uint8_t pos, esc;
Willy Tue39f9392022-06-15 13:24:20 -0700320 size_t i;
Vijay Khemkae7d23d02019-03-08 13:13:40 -0800321 const char *in, *end;
322
323 if (buf == NULL || input == NULL)
324 return -1;
325
326 if (indent >= line_width || indent < 0)
327 return -1;
328
329 in = input;
330 end = in + strlen(input);
331 pos = 0; // line position
332 esc = 0; // escape state
333 i = 0; // buf index
334 while (in != end)
335 {
336 if (i >= buf_size)
337 break;
338
339 if (pos < indent)
340 {
341 // fill indent
342 lbuf[i++] = ' ';
343 pos++;
344 continue;
345 }
346
347 esc = isEscSeq(*in);
348
349 if (!esc && pos == line_width)
350 {
351 lbuf[i++] = LINE_DELIMITER;
352 pos = 0;
353 continue;
354 }
355
356 if (!esc)
357 pos++;
358
359 // fill input data
360 lbuf[i++] = *(in++);
361 }
362
363 // padding
364 while (pos <= line_width)
365 {
366 if (i >= buf_size)
367 break;
368 if (pos < line_width)
369 lbuf[i++] = ' ';
370 else
371 lbuf[i++] = LINE_DELIMITER;
372 pos++;
373 }
374
375 // full
376 if (i >= buf_size)
377 return -1;
378
379 lbuf[i++] = '\0';
380
381 return 0;
382}
383
Vijay Khemka63c99be2020-05-27 19:14:35 -0700384static int chk_cri_sel_update(uint8_t* cri_sel_up)
Vijay Khemkae7d23d02019-03-08 13:13:40 -0800385{
Vijay Khemka63c99be2020-05-27 19:14:35 -0700386 FILE* fp;
Vijay Khemkae7d23d02019-03-08 13:13:40 -0800387 struct stat file_stat;
Karthikeyan Pasupathi39836ff2022-01-17 12:20:06 +0530388 size_t pos = plat_get_fru_sel();
Vijay Khemkae7d23d02019-03-08 13:13:40 -0800389 static uint8_t pre_pos = 0xff;
390
391 fp = fopen("/mnt/data/cri_sel", "r");
392 if (fp)
393 {
394 if ((stat("/mnt/data/cri_sel", &file_stat) == 0) &&
395 (file_stat.st_mtime != frame_sel.mtime || pre_pos != pos))
396 {
397 *cri_sel_up = 1;
398 }
399 else
400 {
401 *cri_sel_up = 0;
402 }
403 fclose(fp);
404 }
405 else
406 {
407 if (frame_sel.buf == NULL || frame_sel.lines != 0 || pre_pos != pos)
408 {
409 *cri_sel_up = 1;
410 }
411 else
412 {
413 *cri_sel_up = 0;
414 }
415 }
416 pre_pos = pos;
417 return 0;
418}
419
Vijay Khemka63c99be2020-05-27 19:14:35 -0700420int plat_udbg_get_frame_info(uint8_t* num)
Vijay Khemkae7d23d02019-03-08 13:13:40 -0800421{
422 *num = 3;
423 return 0;
424}
425
Vijay Khemka63c99be2020-05-27 19:14:35 -0700426int plat_udbg_get_updated_frames(uint8_t* count, uint8_t* buffer)
Vijay Khemkae7d23d02019-03-08 13:13:40 -0800427{
428 uint8_t cri_sel_up = 0;
429 uint8_t info_page_up = 1;
430
431 *count = 0;
432
433 // info page update
434 if (info_page_up == 1)
435 {
436 buffer[*count] = 1;
437 *count += 1;
438 }
439
440 // cri sel update
441 chk_cri_sel_update(&cri_sel_up);
442 if (cri_sel_up == 1)
443 {
444 buffer[*count] = 2;
445 *count += 1;
446 }
447
448 // cri sensor update
449 buffer[*count] = 3;
450 *count += 1;
451
452 return 0;
453}
454
Vijay Khemka63c99be2020-05-27 19:14:35 -0700455int plat_udbg_get_post_desc(uint8_t index, uint8_t* next, uint8_t phase,
456 uint8_t* end, uint8_t* length, uint8_t* buffer)
Vijay Khemkae7d23d02019-03-08 13:13:40 -0800457{
Vijay Khemkacc0d6d92019-08-27 14:51:17 -0700458 nlohmann::json postObj;
459 std::string postCode;
Vijay Khemkae7d23d02019-03-08 13:13:40 -0800460
Vijay Khemkacc0d6d92019-08-27 14:51:17 -0700461 /* Get post description data stored in json file */
462 std::ifstream file(JSON_POST_DATA_FILE);
463 if (file)
464 {
465 file >> postObj;
466 file.close();
467 }
468 else
469 {
470 phosphor::logging::log<phosphor::logging::level::ERR>(
471 "Post code description file not found",
472 phosphor::logging::entry("POST_CODE_FILE=%s", JSON_POST_DATA_FILE));
473 return -1;
474 }
475
476 std::string phaseStr = "PhaseAny";
477 if (postObj.find(phaseStr) == postObj.end())
478 {
479 phaseStr = "Phase" + std::to_string(phase);
480 }
481
482 if (postObj.find(phaseStr) == postObj.end())
483 {
484 phosphor::logging::log<phosphor::logging::level::ERR>(
485 "Post code phase not available",
486 phosphor::logging::entry("PHASE=%d", phase));
487 return -1;
488 }
489
490 auto phaseObj = postObj[phaseStr];
491 int phaseSize = phaseObj.size();
492
493 for (int i = 0; i < phaseSize; i++)
494 {
495 postCode = phaseObj[i][0];
496 if (index == stoul(postCode, nullptr, 16))
497 {
498 std::string postDesc = phaseObj[i][1];
499 *length = postDesc.size();
500 memcpy(buffer, postDesc.data(), *length);
501 buffer[*length] = '\0';
502
503 if (phaseSize != i + 1)
504 {
505 postCode = phaseObj[i + 1][0];
506 *next = stoul(postCode, nullptr, 16);
507 *end = 0;
508 }
509 else
510 {
511 if (postObj.size() != phase)
512 {
513 std::string nextPhaseStr =
514 "Phase" + std::to_string(phase + 1);
515 postCode = postObj[nextPhaseStr][0][0];
516 *next = stoul(postCode, nullptr, 16);
517 *end = 0;
518 }
519 else
520 {
521 *next = 0xff;
522 *end = 1;
523 }
524 }
525
526 return 0;
527 }
528 }
529
530 phosphor::logging::log<phosphor::logging::level::ERR>(
531 "Post code description data not available",
532 phosphor::logging::entry("PHASE_CODE=%d_0x%x", phase, index));
533 return -1;
Vijay Khemkae7d23d02019-03-08 13:13:40 -0800534}
535
Vijay Khemka63c99be2020-05-27 19:14:35 -0700536int plat_udbg_get_gpio_desc(uint8_t index, uint8_t* next, uint8_t* level,
537 uint8_t* def, uint8_t* length, uint8_t* buffer)
Vijay Khemkae7d23d02019-03-08 13:13:40 -0800538{
Vijay Khemka38183d62019-08-28 16:19:33 -0700539 nlohmann::json gpioObj;
540 std::string gpioPin;
541
542 /* Get gpio data stored in json file */
543 std::ifstream file(JSON_GPIO_DATA_FILE);
544 if (file)
545 {
546 file >> gpioObj;
547 file.close();
548 }
549 else
550 {
551 phosphor::logging::log<phosphor::logging::level::ERR>(
552 "GPIO pin description file not found",
553 phosphor::logging::entry("GPIO_PIN_DETAILS_FILE=%s",
554 JSON_GPIO_DATA_FILE));
555 return -1;
556 }
557
558 if (gpioObj.find(DEBUG_GPIO_KEY) == gpioObj.end())
559 {
560 phosphor::logging::log<phosphor::logging::level::ERR>(
561 "GPIO pin details not available",
562 phosphor::logging::entry("GPIO_JSON_KEY=%d", DEBUG_GPIO_KEY));
563 return -1;
564 }
565
566 auto obj = gpioObj[DEBUG_GPIO_KEY];
567 int objSize = obj.size();
568
569 for (int i = 0; i < objSize; i++)
570 {
571 if (obj[i].size() != GPIO_ARRAY_SIZE)
572 {
573 phosphor::logging::log<phosphor::logging::level::ERR>(
574 "Size of gpio array is incorrect",
575 phosphor::logging::entry("EXPECTED_SIZE=%d", GPIO_ARRAY_SIZE));
576 return -1;
577 }
578
579 gpioPin = obj[i][GPIO_PIN_INDEX];
580 if (index == stoul(gpioPin, nullptr, 16))
581 {
582 if (objSize != i + 1)
583 {
584 gpioPin = obj[i + 1][GPIO_PIN_INDEX];
585 *next = stoul(gpioPin, nullptr, 16);
586 }
587 else
588 {
589 *next = 0xff;
590 }
591
592 *level = obj[i][GPIO_LEVEL_INDEX];
593 *def = obj[i][GPIO_DEF_INDEX];
594 std::string gpioDesc = obj[i][GPIO_DESC_INDEX];
595 *length = gpioDesc.size();
596 memcpy(buffer, gpioDesc.data(), *length);
597 buffer[*length] = '\0';
598
599 return 0;
600 }
601 }
602
603 phosphor::logging::log<phosphor::logging::level::ERR>(
604 "GPIO pin description data not available",
605 phosphor::logging::entry("GPIO_PIN=0x%x", index));
606 return -1;
Vijay Khemkae7d23d02019-03-08 13:13:40 -0800607}
608
Willy Tue39f9392022-06-15 13:24:20 -0700609static int udbg_get_cri_sel(uint8_t, uint8_t page, uint8_t* next,
Vijay Khemka63c99be2020-05-27 19:14:35 -0700610 uint8_t* count, uint8_t* buffer)
Vijay Khemkae7d23d02019-03-08 13:13:40 -0800611{
612 int len;
613 int ret;
Willy Tue39f9392022-06-15 13:24:20 -0700614 char line_buff[FRAME_PAGE_BUF_SIZE];
Vijay Khemka63c99be2020-05-27 19:14:35 -0700615 const char* ptr;
616 FILE* fp;
Vijay Khemkae7d23d02019-03-08 13:13:40 -0800617 struct stat file_stat;
Karthikeyan Pasupathi39836ff2022-01-17 12:20:06 +0530618 size_t pos = plat_get_fru_sel();
Vijay Khemkae7d23d02019-03-08 13:13:40 -0800619 static uint8_t pre_pos = FRU_ALL;
620 bool pos_changed = pre_pos != pos;
621
622 pre_pos = pos;
623
624 /* Revisit this */
625 fp = fopen("/mnt/data/cri_sel", "r");
626 if (fp)
627 {
628 if ((stat("/mnt/data/cri_sel", &file_stat) == 0) &&
629 (file_stat.st_mtime != frame_sel.mtime || pos_changed))
630 {
631 // initialize and clear frame
632 frame_sel.init(FRAME_BUFF_SIZE);
633 frame_sel.overwrite = 1;
634 frame_sel.max_page = 20;
635 frame_sel.mtime = file_stat.st_mtime;
636 snprintf(frame_sel.title, 32, "Cri SEL");
637
638 while (fgets(line_buff, FRAME_PAGE_BUF_SIZE, fp))
639 {
640 // Remove newline
641 line_buff[strlen(line_buff) - 1] = '\0';
642 ptr = line_buff;
643 // Find message
644 ptr = strstr(ptr, "local0.err");
645 if (ptr == NULL)
646 {
647 continue;
648 }
649
650 if ((ptr = strrchr(ptr, ':')) == NULL)
651 {
652 continue;
653 }
654 len = strlen(ptr);
655 if (len > 2)
656 {
657 // to skip log string ": "
658 ptr += 2;
659 }
660 // Write new message
661 frame_sel.insert(ptr, 0);
662 }
663 }
664 fclose(fp);
665 }
666 else
667 {
668 // Title only
669 frame_sel.init(FRAME_BUFF_SIZE);
670 snprintf(frame_sel.title, 32, "Cri SEL");
671 frame_sel.mtime = 0;
672 }
673
674 if (page > frame_sel.pages)
675 {
676 return -1;
677 }
678
Vijay Khemka63c99be2020-05-27 19:14:35 -0700679 ret = frame_sel.getPage(page, (char*)buffer, FRAME_PAGE_BUF_SIZE);
Vijay Khemkae7d23d02019-03-08 13:13:40 -0800680 if (ret < 0)
681 {
682 *count = 0;
683 return -1;
684 }
685 *count = (uint8_t)ret;
686
687 if (page < frame_sel.pages)
688 *next = page + 1;
689 else
690 *next = 0xFF; // Set the value of next to 0xFF to indicate this is the
691 // last page
692
693 return 0;
694}
695
Willy Tue39f9392022-06-15 13:24:20 -0700696static int udbg_get_cri_sensor(uint8_t, uint8_t page, uint8_t* next,
Vijay Khemka63c99be2020-05-27 19:14:35 -0700697 uint8_t* count, uint8_t* buffer)
Vijay Khemkae7d23d02019-03-08 13:13:40 -0800698{
Vijay Khemka427b2762019-12-12 12:49:25 -0800699 int ret;
700 double fvalue;
Karthikeyan Pasupathi39836ff2022-01-17 12:20:06 +0530701 size_t pos = plat_get_fru_sel();
Vijay Khemkae7d23d02019-03-08 13:13:40 -0800702
703 if (page == 1)
704 {
705 // Only update frame data while getting page 1
706
707 // initialize and clear frame
708 frame_snr.init(FRAME_BUFF_SIZE);
709 snprintf(frame_snr.title, 32, "CriSensor");
Vijay Khemka427b2762019-12-12 12:49:25 -0800710
711 nlohmann::json senObj;
712
713 /* Get critical sensor names stored in json file */
714 std::ifstream file(JSON_SENSOR_NAMES_FILE);
715 if (file)
716 {
717 file >> senObj;
718 file.close();
719 }
720 else
721 {
722 phosphor::logging::log<phosphor::logging::level::ERR>(
723 "Critical Sensor names file not found",
724 phosphor::logging::entry("CRI_SENSOR_NAMES_FILE=%s",
725 JSON_SENSOR_NAMES_FILE));
726 return -1;
727 }
728
729 /* Get sensors values for all critical sensors */
Vijay Khemka63c99be2020-05-27 19:14:35 -0700730 for (auto& j : senObj.items())
Vijay Khemka427b2762019-12-12 12:49:25 -0800731 {
732 std::string senName = j.key();
733 auto val = j.value();
734
Karthikeyan Pasupathi39836ff2022-01-17 12:20:06 +0530735 if (senName[0] == '_')
736 {
737 senName = std::to_string(pos) + senName;
738 }
739
Vijay Khemka427b2762019-12-12 12:49:25 -0800740 if (ipmi::storage::getSensorValue(senName, fvalue) == 0)
741 {
742 std::stringstream ss;
Vijay Khemkaf43fad42019-12-26 11:47:58 -0800743 int prec = 0; // Default value
744
745 if (val.find("precision") != val.end())
746 prec = val["precision"];
747
748 ss << std::fixed << std::setprecision(prec) << fvalue;
Vijay Khemka427b2762019-12-12 12:49:25 -0800749
750 std::string senStr;
751 if (val.find("short_name") != val.end())
752 senStr = val["short_name"];
753 else
754 senStr = senName;
755
756 senStr += ss.str();
Vijay Khemka58bd5d82019-12-13 11:05:56 -0800757
758 /* Get unit string for sensor and append in output */
759 std::string unitStr;
760 if (ipmi::storage::getSensorUnit(senName, unitStr) == 0)
761 senStr += unitStr;
762
Vijay Khemka427b2762019-12-12 12:49:25 -0800763 frame_snr.append(senStr.c_str(), 0);
764 }
765 else
766 {
767 phosphor::logging::log<phosphor::logging::level::INFO>(
768 "Critical sensor not found",
769 phosphor::logging::entry("CRI_SENSOR_NAME=%s",
770 senName.c_str()));
771 }
772 }
773
Vijay Khemkae7d23d02019-03-08 13:13:40 -0800774 } // End of update frame
775
776 if (page > frame_snr.pages)
777 {
778 return -1;
779 }
780
Vijay Khemka63c99be2020-05-27 19:14:35 -0700781 ret = frame_snr.getPage(page, (char*)buffer, FRAME_PAGE_BUF_SIZE);
Vijay Khemkae7d23d02019-03-08 13:13:40 -0800782 if (ret < 0)
783 {
784 *count = 0;
785 return -1;
786 }
787 *count = (uint8_t)ret;
788
789 if (page < frame_snr.pages)
790 *next = page + 1;
791 else
792 *next = 0xFF; // Set the value of next to 0xFF to indicate this is the
793 // last page
794
795 return 0;
796}
797
Bonnie Loe9baaff2022-11-08 16:36:21 +0800798static int getBiosVer(std::string& ver, size_t hostPosition)
Vijay Khemka88884b82019-08-27 15:23:07 -0700799{
800 nlohmann::json appObj;
801
802 std::ifstream file(JSON_APP_DATA_FILE);
803 if (file)
804 {
805 file >> appObj;
806 file.close();
Bonnie Loe9baaff2022-11-08 16:36:21 +0800807 std::string version_key = KEY_SYSFW_VER + std::to_string(hostPosition);
808
809 if (appObj.find(version_key) != appObj.end())
Vijay Khemka88884b82019-08-27 15:23:07 -0700810 {
Bonnie Loe9baaff2022-11-08 16:36:21 +0800811 ver = appObj[version_key].get<std::string>();
Vijay Khemka88884b82019-08-27 15:23:07 -0700812 return 0;
813 }
814 }
815
816 return -1;
817}
818
Manikandan Elumalai5f8e3432020-12-02 03:46:55 +0530819int sendBicCmd(uint8_t netFn, uint8_t cmd, uint8_t bicAddr,
820 std::vector<uint8_t>& cmdData, std::vector<uint8_t>& respData)
821{
822 static constexpr uint8_t lun = 0;
823
824 auto bus = getSdBus();
825
826 auto method = bus->new_method_call("xyz.openbmc_project.Ipmi.Channel.Ipmb",
827 "/xyz/openbmc_project/Ipmi/Channel/Ipmb",
828 "org.openbmc.Ipmb", "sendRequest");
829 method.append(bicAddr, netFn, lun, cmd, cmdData);
830
831 auto reply = bus->call(method);
832 if (reply.is_method_error())
833 {
834 phosphor::logging::log<phosphor::logging::level::ERR>(
835 "Error reading from BIC");
836 return -1;
837 }
838
839 IpmbMethodType resp;
840 reply.read(resp);
841
842 respData =
843 std::move(std::get<std::remove_reference_t<decltype(respData)>>(resp));
844
845 return 0;
846}
847
Vijay Khemka63c99be2020-05-27 19:14:35 -0700848int sendMeCmd(uint8_t netFn, uint8_t cmd, std::vector<uint8_t>& cmdData,
849 std::vector<uint8_t>& respData)
Vijay Khemkadd14c0f2020-03-18 14:48:13 -0700850{
851 auto bus = getSdBus();
852
853 if (DEBUG)
854 {
855 std::cout << "ME NetFn:cmd " << (int)netFn << ":" << (int)cmd << "\n";
856 std::cout << "ME req data: ";
857 for (auto d : cmdData)
858 {
859 std::cout << d << " ";
860 }
861 std::cout << "\n";
862 }
863
864 auto method = bus->new_method_call("xyz.openbmc_project.Ipmi.Channel.Ipmb",
865 "/xyz/openbmc_project/Ipmi/Channel/Ipmb",
866 "org.openbmc.Ipmb", "sendRequest");
867 method.append(meAddress, netFn, lun, cmd, cmdData);
868
869 auto reply = bus->call(method);
870 if (reply.is_method_error())
871 {
872 phosphor::logging::log<phosphor::logging::level::ERR>(
873 "Error reading from ME");
874 return -1;
875 }
876
877 IpmbMethodType resp;
878 reply.read(resp);
879
880 respData =
881 std::move(std::get<std::remove_reference_t<decltype(respData)>>(resp));
882
883 if (DEBUG)
884 {
885 std::cout << "ME resp data: ";
886 for (auto d : respData)
887 {
888 std::cout << d << " ";
889 }
890 std::cout << "\n";
891 }
892
893 return 0;
894}
895
Potin Lai2ad53982022-10-27 17:02:51 +0800896#ifdef ME_SUPPORT
Karthikeyan Pasupathi98aabdb2022-04-06 17:18:51 +0530897static int getMeStatus(std::string& status, size_t pos)
Vijay Khemka317999d2020-01-02 13:43:42 -0800898{
899 uint8_t cmd = 0x01; // Get Device id command
900 uint8_t netFn = 0x06; // Netfn for APP
901 std::shared_ptr<sdbusplus::asio::connection> bus = getSdBus();
902 std::vector<uint8_t> cmdData;
903
Karthikeyan Pasupathi98aabdb2022-04-06 17:18:51 +0530904 uint8_t meAddr = meAddress;
905 bool platform = isMultiHostPlatform();
906 if (platform == true)
907 {
908 meAddr = ((pos - 1) << 2);
909 }
910
Vijay Khemka317999d2020-01-02 13:43:42 -0800911 auto method = bus->new_method_call("xyz.openbmc_project.Ipmi.Channel.Ipmb",
912 "/xyz/openbmc_project/Ipmi/Channel/Ipmb",
913 "org.openbmc.Ipmb", "sendRequest");
Karthikeyan Pasupathi98aabdb2022-04-06 17:18:51 +0530914 method.append(meAddr, netFn, lun, cmd, cmdData);
Vijay Khemka317999d2020-01-02 13:43:42 -0800915
916 auto reply = bus->call(method);
917 if (reply.is_method_error())
918 {
919 std::cerr << "Error reading from ME\n";
920 return -1;
921 }
922
923 IpmbMethodType resp;
924 reply.read(resp);
925
926 std::vector<uint8_t> data;
927 data = std::get<5>(resp);
928
929 if (DEBUG)
930 {
931 std::cout << "ME Get ID: ";
932 for (size_t d : data)
933 {
934 std::cout << d << " ";
935 }
936 std::cout << "\n";
937 }
938
939 if (data[2] & 0x80)
940 status = "recovery mode";
941 else
942 status = "operation mode";
943
944 return 0;
945}
Potin Lai2ad53982022-10-27 17:02:51 +0800946#endif
Vijay Khemka317999d2020-01-02 13:43:42 -0800947
Willy Tue39f9392022-06-15 13:24:20 -0700948static int udbg_get_info_page(uint8_t, uint8_t page, uint8_t* next,
Vijay Khemka63c99be2020-05-27 19:14:35 -0700949 uint8_t* count, uint8_t* buffer)
Vijay Khemkae7d23d02019-03-08 13:13:40 -0800950{
Willy Tue39f9392022-06-15 13:24:20 -0700951 char line_buff[1000];
952 [[maybe_unused]] char* pres_dev = line_buff;
953 [[maybe_unused]] size_t pos = plat_get_fru_sel();
Vijay Khemkae7d23d02019-03-08 13:13:40 -0800954 int ret;
Karthikeyan Pasupathi98aabdb2022-04-06 17:18:51 +0530955 std::string serialName = "SerialNumber";
956 std::string partName = "PartNumber";
Vijay Khemkae7d23d02019-03-08 13:13:40 -0800957 std::string verDel = "VERSION=";
958 std::string verPath = "/etc/os-release";
Karthikeyan Pasupathi98aabdb2022-04-06 17:18:51 +0530959 size_t hostPosition;
Vijay Khemkae7d23d02019-03-08 13:13:40 -0800960
961 if (page == 1)
962 {
963 // Only update frame data while getting page 1
964
965 // initialize and clear frame
966 frame_info.init(FRAME_BUFF_SIZE);
967 snprintf(frame_info.title, 32, "SYS_Info");
968
Karthikeyan Pasupathi98aabdb2022-04-06 17:18:51 +0530969 bool platform = isMultiHostPlatform();
970 if (platform == true)
971 {
972 hostPosition = getSelectorPosition();
973 }
974
Jayashree Dhanapal4ec80562022-06-28 15:41:47 +0530975 if (hostPosition == BMC_POSITION || hostInstances == "0")
Karthikeyan Pasupathi98aabdb2022-04-06 17:18:51 +0530976 {
977 frame_info.append("FRU:spb", 0);
978 }
Potin Laif24c78e2022-10-27 17:13:14 +0800979 else if (hostPosition != BMC_POSITION &&
980 hostPosition <= getMaxHostPosition())
Karthikeyan Pasupathi98aabdb2022-04-06 17:18:51 +0530981 {
982 std::string data = "FRU:slot" + std::to_string(hostPosition);
983 frame_info.append(data.c_str(), 0);
984 }
985
986 // FRU
Vijay Khemkae7d23d02019-03-08 13:13:40 -0800987 std::string data;
988 frame_info.append("SN:", 0);
989 if (getFruData(data, serialName) != 0)
990 {
991 data = "Not Found";
992 }
993 frame_info.append(data.c_str(), 1);
994 frame_info.append("PN:", 0);
995 if (getFruData(data, partName) != 0)
996 {
997 data = "Not Found";
998 }
999 frame_info.append(data.c_str(), 1);
1000
1001 // LAN
1002 getNetworkData(3, line_buff);
1003 frame_info.append("BMC_IP:", 0);
1004 frame_info.append(line_buff, 1);
1005 getNetworkData(59, line_buff);
1006 frame_info.append("BMC_IPv6:", 0);
1007 frame_info.append(line_buff, 1);
1008
1009 // BMC ver
1010 std::ifstream file(verPath);
1011 if (file)
1012 {
1013 std::string line;
1014 while (std::getline(file, line))
1015 {
1016 if (line.find(verDel) != std::string::npos)
1017 {
1018 std::string bmcVer = line.substr(verDel.size());
1019 frame_info.append("BMC_FW_ver:", 0);
1020 frame_info.append(bmcVer.c_str(), 1);
1021 break;
1022 }
1023 }
1024 }
1025
Karthikeyan Pasupathi98aabdb2022-04-06 17:18:51 +05301026 if (hostPosition != BMC_POSITION)
Vijay Khemka88884b82019-08-27 15:23:07 -07001027 {
Karthikeyan Pasupathi98aabdb2022-04-06 17:18:51 +05301028 // BIOS ver
1029 std::string biosVer;
Bonnie Loe9baaff2022-11-08 16:36:21 +08001030 if (getBiosVer(biosVer, hostPosition) == 0)
Karthikeyan Pasupathi98aabdb2022-04-06 17:18:51 +05301031 {
1032 frame_info.append("BIOS_FW_ver:", 0);
1033 frame_info.append(biosVer.c_str(), 1);
1034 }
Potin Lai2ad53982022-10-27 17:02:51 +08001035
1036#ifdef ME_SUPPORT
Karthikeyan Pasupathi98aabdb2022-04-06 17:18:51 +05301037 // ME status
1038 std::string meStatus;
1039 if (getMeStatus(meStatus, pos) != 0)
1040 {
1041 phosphor::logging::log<phosphor::logging::level::WARNING>(
1042 "Reading ME status failed");
1043 meStatus = "unknown";
1044 }
1045 frame_info.append("ME_status:", 0);
1046 frame_info.append(meStatus.c_str(), 1);
Potin Lai2ad53982022-10-27 17:02:51 +08001047#endif
Vijay Khemka88884b82019-08-27 15:23:07 -07001048 }
Vijay Khemkae7d23d02019-03-08 13:13:40 -08001049
Vijay Khemka317999d2020-01-02 13:43:42 -08001050 /* TBD: Board ID needs implementation */
Vijay Khemkae7d23d02019-03-08 13:13:40 -08001051 // Board ID
1052
1053 // Battery - Use Escape sequence
1054 frame_info.append("Battery:", 0);
1055 frame_info.append(ESC_BAT " ", 1);
1056 // frame_info.append(&frame_info, esc_bat, 1);
1057
1058 // MCU Version - Use Escape sequence
1059 frame_info.append("MCUbl_ver:", 0);
1060 frame_info.append(ESC_MCU_BL_VER, 1);
1061 frame_info.append("MCU_ver:", 0);
1062 frame_info.append(ESC_MCU_RUN_VER, 1);
1063
Vijay Khemkae7d23d02019-03-08 13:13:40 -08001064 // Sys config present device
Karthikeyan Pasupathi10ff3d82022-04-06 16:27:25 +05301065 if (hostPosition != BMC_POSITION)
1066 {
1067 frame_info.append("Sys Conf. info:", 0);
1068
1069 // Dimm info
1070 std::vector<std::string> data;
1071 sysConfig(data, pos);
1072 for (auto& info : data)
1073 {
1074 frame_info.append(info.c_str(), 1);
1075 }
Karthikeyan Pasupathid532fec2022-07-14 14:43:42 +05301076
1077 // Processor info
1078 std::string result;
1079 procInfo(result, pos);
1080 frame_info.append(result.c_str(), 1);
Karthikeyan Pasupathi10ff3d82022-04-06 16:27:25 +05301081 }
Vijay Khemkae7d23d02019-03-08 13:13:40 -08001082
1083 } // End of update frame
1084
1085 if (page > frame_info.pages)
1086 {
1087 return -1;
1088 }
1089
Vijay Khemka63c99be2020-05-27 19:14:35 -07001090 ret = frame_info.getPage(page, (char*)buffer, FRAME_PAGE_BUF_SIZE);
Vijay Khemkae7d23d02019-03-08 13:13:40 -08001091 if (ret < 0)
1092 {
1093 *count = 0;
1094 return -1;
1095 }
1096 *count = (uint8_t)ret;
1097
1098 if (page < frame_info.pages)
1099 *next = page + 1;
1100 else
1101 *next = 0xFF; // Set the value of next to 0xFF to indicate this is the
1102 // last page
1103
1104 return 0;
1105}
1106
Vijay Khemka63c99be2020-05-27 19:14:35 -07001107int plat_udbg_get_frame_data(uint8_t frame, uint8_t page, uint8_t* next,
1108 uint8_t* count, uint8_t* buffer)
Vijay Khemkae7d23d02019-03-08 13:13:40 -08001109{
1110 switch (frame)
1111 {
1112 case 1: // info_page
1113 return udbg_get_info_page(frame, page, next, count, buffer);
1114 case 2: // critical SEL
1115 return udbg_get_cri_sel(frame, page, next, count, buffer);
1116 case 3: // critical Sensor
1117 return udbg_get_cri_sensor(frame, page, next, count, buffer);
1118 default:
1119 return -1;
1120 }
1121}
1122
1123static uint8_t panel_main(uint8_t item)
1124{
1125 // Update item list when select item 0
1126 switch (item)
1127 {
1128 case 1:
1129 return panels[PANEL_BOOT_ORDER].select(0);
1130 case 2:
1131 return panels[PANEL_POWER_POLICY].select(0);
1132 default:
1133 return PANEL_MAIN;
1134 }
1135}
1136
Willy Tue39f9392022-06-15 13:24:20 -07001137static uint8_t panel_boot_order(uint8_t)
Vijay Khemkae7d23d02019-03-08 13:13:40 -08001138{
Willy Tue39f9392022-06-15 13:24:20 -07001139 /* To be implemented */
1140#if 0
Vijay Khemkae7d23d02019-03-08 13:13:40 -08001141 int i;
1142 unsigned char buff[MAX_VALUE_LEN], pickup, len;
Karthikeyan Pasupathi39836ff2022-01-17 12:20:06 +05301143 size_t pos = plat_get_fru_sel();
Willy Tue39f9392022-06-15 13:24:20 -07001144 if (pos != FRU_ALL && pal_get_boot_order(pos, buff, buff, &len) == 0)
1145 {
1146 if (item > 0 && item < SIZE_BOOT_ORDER)
1147 {
1148 pickup = buff[item];
1149 while (item > 1)
1150 {
1151 buff[item] = buff[item - 1];
1152 item--;
1153 }
1154 buff[item] = pickup;
1155 buff[0] |= 0x80;
1156 pal_set_boot_order(pos, buff, buff, &len);
Vijay Khemkae7d23d02019-03-08 13:13:40 -08001157
Willy Tue39f9392022-06-15 13:24:20 -07001158 // refresh items
1159 return panels[PANEL_BOOT_ORDER].select(0);
1160 }
Vijay Khemkae7d23d02019-03-08 13:13:40 -08001161
Willy Tue39f9392022-06-15 13:24:20 -07001162 // '*': boot flags valid, BIOS has not yet read
1163 snprintf(panels[PANEL_BOOT_ORDER].item_str[0], 32, "Boot Order%c",
1164 (buff[0] & 0x80) ? '*' : '\0');
Vijay Khemkae7d23d02019-03-08 13:13:40 -08001165
Willy Tue39f9392022-06-15 13:24:20 -07001166 for (i = 1; i < SIZE_BOOT_ORDER; i++)
1167 {
1168 switch (buff[i])
1169 {
1170 case 0x0:
1171 snprintf(panels[PANEL_BOOT_ORDER].item_str[i], 32,
1172 " USB device");
1173 break;
1174 case 0x1:
1175 snprintf(panels[PANEL_BOOT_ORDER].item_str[i], 32,
1176 " Network v4");
1177 break;
1178 case (0x1 | 0x8):
1179 snprintf(panels[PANEL_BOOT_ORDER].item_str[i], 32,
1180 " Network v6");
1181 break;
1182 case 0x2:
1183 snprintf(panels[PANEL_BOOT_ORDER].item_str[i], 32,
1184 " SATA HDD");
1185 break;
1186 case 0x3:
1187 snprintf(panels[PANEL_BOOT_ORDER].item_str[i], 32,
1188 " SATA-CDROM");
1189 break;
1190 case 0x4:
1191 snprintf(panels[PANEL_BOOT_ORDER].item_str[i], 32,
1192 " Other");
1193 break;
1194 default:
1195 panels[PANEL_BOOT_ORDER].item_str[i][0] = '\0';
1196 break;
1197 }
1198 }
Vijay Khemkae7d23d02019-03-08 13:13:40 -08001199
Willy Tue39f9392022-06-15 13:24:20 -07001200 // remove empty items
1201 for (i--;
1202 (strlen(panels[PANEL_BOOT_ORDER].item_str[i]) == 0) && (i > 0);
1203 i--)
1204 ;
Vijay Khemkae7d23d02019-03-08 13:13:40 -08001205
Willy Tue39f9392022-06-15 13:24:20 -07001206 panels[PANEL_BOOT_ORDER].item_num = i;
1207 }
1208 else
1209 {
1210 panels[PANEL_BOOT_ORDER].item_num = 0;
1211 }
1212#endif
Vijay Khemkae7d23d02019-03-08 13:13:40 -08001213 return PANEL_BOOT_ORDER;
1214}
1215
Willy Tue39f9392022-06-15 13:24:20 -07001216static uint8_t panel_power_policy(uint8_t)
Vijay Khemkae7d23d02019-03-08 13:13:40 -08001217{
Willy Tue39f9392022-06-15 13:24:20 -07001218/* To be cleaned */
1219#if 0
Vijay Khemkae7d23d02019-03-08 13:13:40 -08001220 uint8_t buff[32] = {0};
1221 uint8_t res_len;
Karthikeyan Pasupathi39836ff2022-01-17 12:20:06 +05301222 size_t pos = plat_get_fru_sel();
Vijay Khemkae7d23d02019-03-08 13:13:40 -08001223 uint8_t policy;
Willy Tue39f9392022-06-15 13:24:20 -07001224 uint8_t pwr_policy_item_map[3] = {POWER_CFG_ON, POWER_CFG_LPS,
1225 POWER_CFG_OFF};
Vijay Khemkae7d23d02019-03-08 13:13:40 -08001226
Willy Tue39f9392022-06-15 13:24:20 -07001227 if (pos != FRU_ALL)
1228 {
1229 if (item > 0 && item <= sizeof(pwr_policy_item_map))
1230 {
1231 policy = pwr_policy_item_map[item - 1];
1232 pal_set_power_restore_policy(pos, &policy, NULL);
1233 }
1234 pal_get_chassis_status(pos, NULL, buff, &res_len);
1235 policy = (((uint8_t)buff[0]) >> 5) & 0x7;
1236 snprintf(panels[PANEL_POWER_POLICY].item_str[1], 32, "%cPower On",
1237 policy == POWER_CFG_ON ? '*' : ' ');
1238 snprintf(panels[PANEL_POWER_POLICY].item_str[2], 32, "%cLast State",
1239 policy == POWER_CFG_LPS ? '*' : ' ');
1240 snprintf(panels[PANEL_POWER_POLICY].item_str[3], 32, "%cPower Off",
1241 policy == POWER_CFG_OFF ? '*' : ' ');
1242 panels[PANEL_POWER_POLICY].item_num = 3;
1243 }
1244 else
1245 {
1246 panels[PANEL_POWER_POLICY].item_num = 0;
1247 }
1248#endif
Vijay Khemkae7d23d02019-03-08 13:13:40 -08001249 return PANEL_POWER_POLICY;
1250}
1251
1252int plat_udbg_control_panel(uint8_t panel, uint8_t operation, uint8_t item,
Vijay Khemka63c99be2020-05-27 19:14:35 -07001253 uint8_t* count, uint8_t* buffer)
Vijay Khemkae7d23d02019-03-08 13:13:40 -08001254{
1255 if (panel > panelNum || panel < PANEL_MAIN)
1256 return IPMI_CC_PARM_OUT_OF_RANGE;
1257
1258 // No more item; End of item list
1259 if (item > panels[panel].item_num)
1260 return IPMI_CC_PARM_OUT_OF_RANGE;
1261
1262 switch (operation)
1263 {
1264 case 0: // Get Description
1265 break;
1266 case 1: // Select item
1267 panel = panels[panel].select(item);
1268 item = 0;
1269 break;
1270 case 2: // Back
1271 panel = panels[panel].parent;
1272 item = 0;
1273 break;
1274 default:
1275 return IPMI_CC_PARM_OUT_OF_RANGE;
1276 }
1277
1278 buffer[0] = panel;
1279 buffer[1] = item;
1280 buffer[2] = strlen(panels[panel].item_str[item]);
1281 if (buffer[2] > 0 && (buffer[2] + 3) < FRAME_PAGE_BUF_SIZE)
1282 {
1283 memcpy(&buffer[3], panels[panel].item_str[item], buffer[2]);
1284 }
1285 *count = buffer[2] + 3;
1286 return IPMI_CC_OK;
1287}
1288
1289} // end of namespace ipmi