cmd: remove sparc-only virtinfo
[unleashed.git] / usr / src / cmd / picl / plugins / sun4u / snowbird / lib / fruaccess / piclsmc.c
blobd30e610691fe0525a2080ad64caeeaabff948530
1 /*
2 * CDDL HEADER START
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License, Version 1.0 only
6 * (the "License"). You may not use this file except in compliance
7 * with the License.
9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10 * or http://www.opensolaris.org/os/licensing.
11 * See the License for the specific language governing permissions
12 * and limitations under the License.
14 * When distributing Covered Code, include this CDDL HEADER in each
15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16 * If applicable, add the following below this CDDL HEADER, with the
17 * fields enclosed by brackets "[]" replaced with your own identifying
18 * information: Portions Copyright [yyyy] [name of copyright owner]
20 * CDDL HEADER END
23 * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
27 #pragma ident "%Z%%M% %I% %E% SMI"
30 * These routines in this file are used to interact with SMC driver to
31 * read and write FRUID data
34 #include <stdio.h>
35 #include <unistd.h>
36 #include <string.h>
37 #include <strings.h>
38 #include <stdarg.h>
39 #include <synch.h>
40 #include <thread.h>
41 #include <sys/types.h>
42 #include <sys/stat.h>
43 #include <fcntl.h>
44 #include <syslog.h>
45 #include <stropts.h>
46 #include <poll.h>
47 #include <smclib.h>
48 #include "fru_access_impl.h"
50 #define POLL_TIMEOUT 10000
51 #define FRUID_CHECK_POLL_TIMEOUT 5000
52 #define SIZE_TO_READ_WRITE 20
54 /* IPMI fru spec Storage definition version 1.0, rev 1.1 */
55 #define IPMI_COMMON_HEADER_SIZE 8
56 #define IPMI_VERSION 1
57 #define CMN_HDR_VERSION_MASK 0x0
58 #define CMN_HDR_OFFSET 0x0
59 #define BD_MFR_OFFSET 6
60 #define BD_FIELDS_SIZE 6
61 #define AREA_TERMINATION_INDICATOR 0xc1
63 /* type encoding */
64 #define BINARY_TYPE 0x0
65 #define BCDPLUS_TYPE 0x1
66 #define SIX_BITASCII_TYPE 0x2
67 #define UNICODE_TYPE 0x3
69 /* for ascii conversion */
70 #define ASCII_MAP 0x20
71 #define BIT_MASK1 0x3f
72 #define BIT_MASK2 0x0f
73 #define BIT_MASK3 0x03
75 #define SUN_NAME "SUN MICROSYSTEMS, INC."
76 #define SUN_JEDEC_CODE 0x3e
77 #define MANR_MAX_LENGTH 80
78 #define FRU_DATA_MAX_SIZE 100
80 /* IPMI commands */
81 #define IPMI_GET_DEVICE_ID 0x1
82 #define FRU_DEVICE_ID 0x0
83 #define READ_FRU_INVENTORY_INFO 0x10
84 #define READ_FRU_INVENTORY_DATA 0x11
85 #define WRITE_FRU_INVENTORY_DATA 0x12
87 #define TMP_BUFFER_SIZE 10
88 #define BYTE_TO_READ_SUN_CHK 5
90 typedef struct {
91 uint8_t internal; /* internal use area */
92 uint8_t chassis; /* chassis info area */
93 uint8_t board; /* board area */
94 uint8_t product; /* product info area */
95 uint8_t records; /* multirecord area */
96 } fruid_offset_t;
98 extern void get_fru_data_info(int, int, format_t *);
99 static void convert_to_ascii(uint8_t [], uint8_t [], int, int);
100 static void bcdplus_to_ascii(uint8_t [], uint8_t [], int);
101 static time_t get_utc_time(uint8_t []);
102 static uint8_t cpu_no = 0;
105 * Routine to read FRUID information from BMC
107 static int
108 get_alarm_fru_data(int offset, int size, void *buffer, format_t *format)
110 uint8_t datap[5];
111 sc_reqmsg_t req_pkt;
112 sc_rspmsg_t res_pkt;
114 if (buffer == NULL) {
115 return (-1);
117 bzero(buffer, size);
119 datap[0] = 0x7; /* bus id */
120 datap[1] = 0xa0; /* slave address */
121 datap[2] = size; /* count */
122 datap[3] = offset >> 8; /* MSB */
123 datap[4] = (uint8_t)offset; /* LSB */
125 (void) smc_init_ipmi_msg(&req_pkt, SMC_MASTER_WR_RD_I2C,
126 FRUACCESS_MSG_ID, 5, datap, DEFAULT_SEQN, format->dest,
127 SMC_NETFN_APP_REQ, SMC_BMC_LUN);
129 if (smc_send_msg(DEFAULT_FD, &req_pkt, &res_pkt,
130 POLL_TIMEOUT) != SMC_SUCCESS) {
131 return (-1);
133 /* check the completion code */
134 if (res_pkt.data[7] != 0) {
135 return (-1);
138 (void) memcpy(buffer, &(res_pkt.data[8]), size);
139 return (0);
143 * Routine to read FRUID information from other boards
145 static int
146 get_fru_data(int offset, int size, void *buffer, format_t *format)
148 sc_reqmsg_t req_pkt;
149 sc_rspmsg_t res_pkt;
150 uint8_t datap[4];
151 int ipmi = 0;
153 if (buffer == NULL) {
154 return (-1);
157 /* figure out if onboard access or ipmb access */
158 if (format->src == format->dest) {
159 ipmi = 0;
160 } else {
161 ipmi = 1;
164 switch (ipmi) {
166 case 0: /* on board info (local i2c) */
168 SC_MSG_CMD(&req_pkt) = SMC_EEPROM_READ;
169 SC_MSG_LEN(&req_pkt) = 4;
170 SC_MSG_ID(&req_pkt) = FRUACCESS_MSG_ID;
172 /* data field for request */
173 req_pkt.data[0] = format->sun_device_id; /* device id */
174 req_pkt.data[1] = (uint8_t)offset; /* (LSB) */
175 req_pkt.data[3] = size;
177 if (format->format == SUN_FORMAT) {
178 req_pkt.data[2] = offset >> 8;
179 } else {
180 req_pkt.data[2] = 0x0; /* (MSB) always 0x0 for IPMI */
183 /* make a call to smc library to send cmd */
184 if (smc_send_msg(DEFAULT_FD, &req_pkt, &res_pkt,
185 POLL_TIMEOUT) != SMC_SUCCESS) {
186 return (-1);
189 if (SC_MSG_LEN(&res_pkt) != size) {
190 return (-1);
192 (void) memcpy(buffer, res_pkt.data, size);
193 return (0);
195 default:
197 /* data for request packet */
198 datap[0] = format->sun_device_id; /* device id */
199 datap[1] = (uint8_t)offset; /* LSB */
200 datap[3] = size; /* bytes to read */
201 if (format->format == SUN_FORMAT) {
202 datap[2] = offset >> 8;
203 } else {
204 datap[2] = 0x0; /* (MSB) always 0x0 for IPMI */
207 (void) smc_init_ipmi_msg(&req_pkt, READ_FRU_INVENTORY_DATA,
208 FRUACCESS_MSG_ID, 4, datap, DEFAULT_SEQN,
209 format->dest, SMC_NETFN_STORAGE_REQ, format->sun_lun);
211 if (smc_send_msg(DEFAULT_FD, &req_pkt, &res_pkt,
212 POLL_TIMEOUT) != SMC_SUCCESS) {
213 return (-1);
215 /* check the completion code */
216 if (res_pkt.data[7] != 0) {
217 return (-1);
220 /* check the size */
221 if (res_pkt.data[8] != size) {
222 return (-1);
225 (void) memcpy(buffer, &(res_pkt.data[9]), size);
226 return (0);
231 * routine to read the IPMI common header field
233 static int
234 read_common_header(fruid_offset_t *offset, format_t *format)
236 int ret = 0;
237 uint8_t data[FRU_DATA_MAX_SIZE];
239 ret = get_fru_data(CMN_HDR_OFFSET, IPMI_COMMON_HEADER_SIZE, data,
240 format);
241 if (ret < 0) {
242 return (-1);
245 /* version check */
246 if ((data[0] | CMN_HDR_VERSION_MASK) != 1) {
247 return (-1);
250 offset->internal = data[1] * 8;
251 offset->chassis = data[2] * 8;
252 offset->board = data[3] * 8;
253 offset->product = data[4] * 8;
254 offset->records = data[5] * 8;
256 return (0);
260 * Read the values of each field based on FORMAT
262 /* ARGSUSED */
263 static int
264 read_bd_fields(uint8_t *field, int offset, format_t *format)
267 int ret, encode_type = 0x0, len, length, extra_bytes, alloc_size;
268 uint8_t *store;
269 uint8_t data[FRU_DATA_MAX_SIZE];
271 bzero(field, MANR_MAX_LENGTH);
273 ret = get_fru_data(offset, BD_FIELDS_SIZE, data, format);
274 if (ret < 0) {
275 return (-1);
278 if (data[0] == AREA_TERMINATION_INDICATOR) {
279 return (0);
282 encode_type = data[0] >> 6;
283 len = data[0] & 0x3f;
284 if (len <= 0) {
285 return (0);
288 ret = get_fru_data(offset+1, len, data, format);
289 if (ret < 0) {
290 return (-1);
293 switch (encode_type) {
295 case SIX_BITASCII_TYPE:
297 length = len - (len % 3);
298 extra_bytes = len % 3;
299 alloc_size = ((length/3) * 4) + extra_bytes;
300 store = (uint8_t *)malloc(sizeof (uint8_t) * alloc_size);
301 if (store == NULL) {
302 return (-1);
304 convert_to_ascii(data, store, len, extra_bytes);
305 break;
307 case BCDPLUS_TYPE:
309 alloc_size = len * 2;
310 store = (uint8_t *)malloc(sizeof (uint8_t) * alloc_size);
311 if (store == NULL) {
312 return (-1);
315 bcdplus_to_ascii(data, store, len);
316 break;
318 case BINARY_TYPE:
319 case UNICODE_TYPE:
320 default:
321 return (-1);
324 (void) memcpy(field, store, alloc_size);
325 free(store);
326 return (len);
329 static int
330 read_board_info(uint8_t board_offset, payload_t *manr, format_t *format)
332 time_t time;
333 uint8_t *buffer;
334 uint8_t mfg_time[4];
335 uint8_t data[FRU_DATA_MAX_SIZE];
336 int ret = 0, current_offset = 0x0;
337 int bd_area_len = 0;
339 /* read version, length, lang code, mfg. time */
340 ret = get_fru_data(board_offset, BD_FIELDS_SIZE, data, format);
342 if (ret < 0) {
343 return (-1);
346 /* version check */
347 if ((data[0] | CMN_HDR_VERSION_MASK) != 1) {
348 return (-1);
351 /* byte 2 is lang code */
352 bd_area_len = data[1] * 8;
353 mfg_time[3] = data[3];
354 mfg_time[2] = data[4];
355 mfg_time[1] = data[5];
356 mfg_time[0] = 0x0;
357 time = get_utc_time(mfg_time);
359 /* fill the timestamp into manr */
360 (void) memcpy(manr->timestamp, &time, MANR_TIME_LEN);
362 if (bd_area_len < BD_MFR_OFFSET) {
363 return (-1);
365 buffer = (uint8_t *)malloc(sizeof (uint8_t) * MANR_MAX_LENGTH);
366 if (buffer == NULL) {
367 return (-1);
370 /* read the board info */
371 current_offset += board_offset + BD_MFR_OFFSET;
372 current_offset += read_bd_fields(buffer, current_offset, format);
374 if (strncmp(SUN_NAME, (char *)buffer, sizeof (SUN_NAME)) == 0) {
375 manr->vendor_name[0] = 0x00;
376 manr->vendor_name[1] = 0x3e;
377 } else {
378 manr->vendor_name[0] = 0x00;
379 manr->vendor_name[1] = 0x00;
382 current_offset += 1; /* for length/type field */
384 current_offset += read_bd_fields(buffer, current_offset, format);
385 current_offset += 1; /* for length/type field */
386 (void) memcpy(manr->fru_short_name, buffer, MANR_FRUNAME_LEN);
388 current_offset += read_bd_fields(buffer, current_offset, format);
389 current_offset += 1; /* for length/type field */
390 (void) memcpy(manr->sun_serial_no, buffer, MANR_SERIALNUM_LEN);
392 current_offset += read_bd_fields(buffer, current_offset, format);
393 current_offset += 1; /* for length/type field */
394 (void) memcpy(manr->sun_part_no, buffer, MANR_PARTNUM_LEN);
397 * We dont need the FRU FILE ID, so just skip the field
398 * and get the offset to read the custom MFG. info fields
400 current_offset += read_bd_fields(buffer, current_offset, format);
401 current_offset += 1; /* for length/type field */
403 current_offset += read_bd_fields(buffer, current_offset, format);
404 current_offset += 1; /* for length/type field */
406 /* read the custom mfg. info fields */
407 current_offset += read_bd_fields(buffer, current_offset, format);
408 current_offset += 1; /* for length/type field */
409 (void) memcpy(manr->manufacture_loc, buffer, MANR_MFRLOC_LEN);
411 current_offset += read_bd_fields(buffer, current_offset, format);
412 (void) memcpy(manr->fru_descr, buffer, MANR_FRUDESCR_LEN);
414 free(buffer);
415 return (0);
419 * Read the IPMI information from hardware and translate it into
420 * MANR(SUN format)
423 get_manr(format_t *format, payload_t *manr)
425 int ret = 0;
426 fruid_offset_t *offset = NULL;
428 offset = (fruid_offset_t *)malloc(sizeof (fruid_offset_t));
429 if (offset == NULL) {
430 return (-1);
433 ret = read_common_header(offset, format);
434 if (ret != 0) {
435 free(offset);
436 return (-1);
439 if (offset->board != 0) {
440 ret = read_board_info(offset->board, manr, format);
443 free(offset);
444 return (ret);
447 static void
448 convert_to_ascii(uint8_t data [], uint8_t store[],
449 int length, int extra_bytes)
451 uint8_t x, y;
452 int index = 0;
453 int i, idx = length - (length % 3);
455 for (i = 0; ; i += 3) {
457 x = 0x0;
458 y = 0x0;
460 if (i == idx && extra_bytes == 0) {
461 break;
464 /* get the first six bits */
465 x = (data[i] & BIT_MASK1);
466 x += ASCII_MAP;
467 store[index] = x;
469 if (i == idx && extra_bytes == 1) {
470 break;
474 * get last 2 bits of first byte and first
475 * 4 bits of second byte
478 x = (data[i] >> 6);
479 y = (data[i + 1] & BIT_MASK2) << 2;
480 x |= y + ASCII_MAP;
481 store[index+1] = x;
483 if (i == idx) {
484 break;
487 /* get last 4 bits of second byte and 2 bits of last byte */
488 x = data[i + 1] >> 4;
489 y = (data[i + 2] & BIT_MASK3) << 4;
490 x |= y + ASCII_MAP;
491 store[index+2] = x;
493 /* get last six bits of third byte */
494 store[index + 3] = (data[i + 2] >> 2) + ASCII_MAP;
495 index += 4;
499 static void
500 bcdplus_to_ascii(uint8_t data[], uint8_t store[], int len)
502 int i, j, index = 0;
503 uint8_t tmp = 0;
505 struct {
506 int a:4;
507 int b:4;
508 } val;
510 for (i = 0; i < len; i++) {
511 (void) memcpy(&val, &data[i], 1);
512 for (j = 0; j < 2; j++) {
513 if (j == 0) {
514 tmp = val.a;
515 } else
516 tmp = val.b;
518 if (tmp <= 9) {
519 /* ascii conversion */
520 store[index++] = tmp + 48;
521 continue;
524 switch (tmp) {
526 case 0xa:
527 store[index++] = ' ';
528 break;
529 case 0xb:
530 store[index++] = '-';
531 break;
532 case 0xc:
533 store[index++] = '.';
534 break;
535 default:
536 store[index++] = ' ';
542 /* converts ipmi format time to UTC time (unix 32 bit timestamp) */
543 static time_t
544 get_utc_time(uint8_t data [])
546 time_t time;
547 struct tm tm1;
548 uint32_t ipmi_time;
550 (void) memcpy(&ipmi_time, data, 4);
552 ipmi_time *= 60; /* convert into seconds */
554 /* get UTC time for 0:00 1/1/96 (ipmi epoch) */
555 tm1.tm_sec = 0;
556 tm1.tm_min = 0;
557 tm1.tm_hour = 0;
558 tm1.tm_mday = 1;
559 tm1.tm_mon = 0;
560 tm1.tm_year = 96;
562 time = mktime(&tm1);
563 time += ipmi_time;
565 return (time);
569 * routine to write information to BMC
571 static int
572 write_alarm_fru_data(const void *buffer, size_t size,
573 off_t offset, format_t *format)
575 sc_reqmsg_t req_pkt;
576 sc_rspmsg_t res_pkt;
577 uint8_t *datap = NULL;
579 if (buffer == NULL) {
580 return (-1);
582 datap = (uint8_t *)malloc(sizeof (uint8_t) * (size + 5));
583 if (datap == NULL) {
584 return (-1);
587 datap[0] = 0x7; /* bus id */
588 datap[1] = 0xa0; /* slave address */
589 datap[2] = 0; /* count */
590 datap[3] = offset >> 8; /* MSB */
591 datap[4] = (uint8_t)offset; /* LSB */
592 (void) memcpy((void *)&(datap[5]), buffer, size);
594 /* initialize ipmi request packet */
595 (void) smc_init_ipmi_msg(&req_pkt, SMC_MASTER_WR_RD_I2C,
596 FRUACCESS_MSG_ID, (5 + size), datap, DEFAULT_SEQN,
597 format->dest, SMC_NETFN_APP_REQ, SMC_BMC_LUN);
598 free(datap);
600 /* send ipmi request packet */
601 if (smc_send_msg(DEFAULT_FD, &req_pkt, &res_pkt,
602 POLL_TIMEOUT) != SMC_SUCCESS) {
603 return (-1);
605 /* check the completion code */
606 if (res_pkt.data[7] != 0) {
607 return (-1);
609 return (0);
612 static int
613 write_fru_data(const void *buffer, size_t size,
614 off_t offset, format_t *format)
616 int ipmi = 0;
617 sc_reqmsg_t req_pkt;
618 sc_rspmsg_t res_pkt;
619 uint8_t *datap = NULL;
621 if (buffer == NULL) {
622 return (-1);
625 if (format->src == format->dest) {
626 ipmi = 0;
627 } else {
628 ipmi = 1;
631 switch (ipmi) {
633 case 0: /* on board info (local i2c) */
635 SC_MSG_CMD(&req_pkt) = SMC_EEPROM_WRITE;
636 SC_MSG_LEN(&req_pkt) = 4 + size;
637 SC_MSG_ID(&req_pkt) = FRUACCESS_MSG_ID;
639 /* data field for request */
640 req_pkt.data[0] = format->sun_device_id; /* device id */
641 req_pkt.data[1] = offset; /* (LSB) */
642 req_pkt.data[3] = size;
643 if (format->format == SUN_FORMAT) {
644 req_pkt.data[2] = offset >> 8;
645 } else {
646 req_pkt.data[2] = 0x0; /* (MSB) always 0x0 for IPMI */
648 (void) memcpy((void *)&(req_pkt.data[4]), buffer, size);
650 /* make a call to smc library to send cmd */
651 if (smc_send_msg(DEFAULT_FD, &req_pkt, &res_pkt,
652 POLL_TIMEOUT) != SMC_SUCCESS) {
653 return (-1);
655 break;
657 default: /* read data from remote device (ipmi) */
658 datap = (uint8_t *)malloc(sizeof (uint8_t) * (size + 4));
659 if (datap == NULL) {
660 return (-1);
663 datap[0] = format->sun_device_id; /* device id */
664 datap[1] = offset; /* LSB */
665 datap[3] = size; /* nbytes */
666 if (format->format == SUN_FORMAT) {
667 datap[2] = offset >> 8;
668 } else {
669 datap[2] = 0x0; /* (MSB) always 0x0 for IPMI */
671 (void) memcpy((void *)&(datap[4]), buffer, size);
673 (void) smc_init_ipmi_msg(&req_pkt, WRITE_FRU_INVENTORY_DATA,
674 FRUACCESS_MSG_ID, (4 + size), datap, DEFAULT_SEQN,
675 format->dest, SMC_NETFN_STORAGE_REQ, format->sun_lun);
676 free(datap);
678 if (smc_send_msg(DEFAULT_FD, &req_pkt, &res_pkt,
679 POLL_TIMEOUT) != SMC_SUCCESS) {
680 return (-1);
682 /* check the completion code */
683 if (res_pkt.data[7] != 0) {
684 return (-1);
686 break;
687 } /* end of switch */
688 return (0);
692 * This routine splits the data to write into smaller chunks and
693 * write it to FRUID chip using SMC drv APIs
696 /* ARGSUSED */
697 ssize_t
698 pwrite_new(int fd, const void *buffer, size_t size,
699 off_t offset, format_t *format)
701 int ret;
702 int index = 0;
703 size_t bytes = 0;
704 off_t next_offset = 0x0;
705 off_t curr_offset = offset;
706 size_t bytes_to_write = size;
707 uint8_t *data;
708 int retry = 3;
709 int (* func_ptr)(const void *, size_t, off_t, format_t *);
711 if (format->dest == 0x20) {
712 func_ptr = write_alarm_fru_data;
713 } else {
714 func_ptr = write_fru_data;
717 data = (uint8_t *)buffer;
718 while (bytes_to_write != 0) {
720 retry = 3;
721 ret = 1;
723 if (bytes_to_write > SIZE_TO_READ_WRITE) {
724 bytes = SIZE_TO_READ_WRITE;
725 next_offset = curr_offset + SIZE_TO_READ_WRITE;
726 } else {
727 bytes = bytes_to_write;
730 bytes_to_write = bytes_to_write - bytes;
731 while ((ret != 0) && (retry != 0)) {
732 ret = (*func_ptr)((void *)&data[index],
733 bytes, curr_offset, format);
734 retry--;
736 if (ret != 0) {
737 return (ret);
739 index = index + bytes;
740 curr_offset = next_offset;
742 return (size);
746 * This routine reads the data in smaller chunks and
747 * sends it to upper layer(frudata plugin) in the sw stack
749 /* ARGSUSED */
750 ssize_t
751 pread_new(int fd, void *buffer, size_t size,
752 off_t offset, format_t *format)
754 int ret;
755 int index = 0;
756 size_t bytes = 0;
757 off_t next_offset = 0x0;
758 off_t curr_offset = offset;
759 size_t bytes_to_read = size;
760 uint8_t *data;
761 int retry = 3;
762 int (* func_ptr)(int, int, void *, format_t *);
764 if (format->dest == 0x20) {
765 func_ptr = get_alarm_fru_data;
766 } else {
767 func_ptr = get_fru_data;
770 data = (uint8_t *)buffer;
772 while (bytes_to_read != 0) {
774 retry = 3;
775 ret = 1;
777 if (bytes_to_read > SIZE_TO_READ_WRITE) {
778 bytes = SIZE_TO_READ_WRITE;
779 next_offset = curr_offset + SIZE_TO_READ_WRITE;
780 } else {
781 bytes = bytes_to_read;
784 bytes_to_read = bytes_to_read - bytes;
786 while ((ret != 0) && (retry != 0)) {
787 ret = (* func_ptr)(curr_offset, bytes,
788 (void *) &data[index], format);
789 retry--;
791 if (ret != 0) {
792 return (ret);
794 index = index + bytes;
795 curr_offset = next_offset;
797 return (size);
801 * routine to check if IPMI fruid info is available,
802 * return 0: IPMI fruid not present
803 * return 1: IPMI fruid present
805 static int
806 is_ipmi_fru_data_available(int src, int dest)
808 sc_reqmsg_t req_pkt;
809 sc_rspmsg_t res_pkt;
810 uint8_t datap[5];
812 /* on board access */
813 if (src == dest) {
815 SC_MSG_CMD(&req_pkt) = SMC_EEPROM_READ;
816 SC_MSG_LEN(&req_pkt) = 4;
817 SC_MSG_ID(&req_pkt) = FRUACCESS_MSG_ID;
819 /* data field for request */
820 req_pkt.data[0] = 0x0; /* eeprom number (ipmi format) */
821 req_pkt.data[1] = CMN_HDR_OFFSET; /* (LSB) */
822 req_pkt.data[2] = 0x0; /* (MSB) always 0x0 for IPMI */
823 req_pkt.data[3] = IPMI_COMMON_HEADER_SIZE;
825 /* make a call to smc library to send cmd */
826 if (smc_send_msg(DEFAULT_FD, &req_pkt, &res_pkt,
827 POLL_TIMEOUT) != SMC_SUCCESS) {
828 return (0);
831 /* version check */
832 if (res_pkt.data[0] != IPMI_VERSION) {
833 return (0);
834 } else {
835 return (1);
839 /* ipmi access */
840 datap[0] = FRU_DEVICE_ID; /* fru device id - always */
841 datap[1] = 0x0; /* LSB */
842 datap[2] = 0x0; /* MSB */
843 datap[3] = 8; /* bytes to read */
845 (void) smc_init_ipmi_msg(&req_pkt, READ_FRU_INVENTORY_DATA,
846 FRUACCESS_MSG_ID, 4, datap, DEFAULT_SEQN,
847 IPMB_ADDR(dest), SMC_NETFN_STORAGE_REQ, SMC_BMC_LUN);
849 if (smc_send_msg(DEFAULT_FD, &req_pkt, &res_pkt,
850 FRUID_CHECK_POLL_TIMEOUT) != SMC_SUCCESS) {
851 return (0);
854 if (res_pkt.data[9] == IPMI_VERSION) {
855 return (1);
856 } else {
857 return (0);
862 * routine to check if fruid info is available on BMC,
863 * return 0: fruid not present
864 * return 1: fruid present
866 static int
867 is_alarm_frudata_available(format_t *fru_format)
869 int ret;
870 char buffer[TMP_BUFFER_SIZE];
871 int fd = -1;
872 format_t format;
874 bzero(buffer, sizeof (buffer));
875 format.src = fru_format->src;
876 format.dest = fru_format->dest;
877 format.sun_device_id = 0x0;
878 format.sun_lun = 0x0;
879 format.format |= SUN_FORMAT;
881 /* passing dummy fd */
882 /* for now read the first 3 bytes and check the info */
883 ret = pread_new(fd, (void *) buffer, 3, STATIC_OFFSET, &format);
884 if (ret < 0) {
885 return (0);
888 if (buffer[0] != SECTION_HDR_TAG) {
889 fru_format->format = NO_FRUDATA;
890 return (0);
893 fru_format->format = SUN_FORMAT;
894 fru_format->sun_device_id = 0x0;
895 fru_format->sun_lun = 0x0;
896 return (1);
900 * checks if the remote device intelligent device (IPMI capable) or not
901 * return 0: not ipmi capable
902 * return 1: ipmi capable
904 static int
905 is_ipmi_capable(int src, int dest)
907 sc_reqmsg_t req_pkt;
908 sc_rspmsg_t res_pkt;
910 if (src == dest) {
911 return (1);
914 (void) smc_init_ipmi_msg(&req_pkt, IPMI_GET_DEVICE_ID,
915 FRUACCESS_MSG_ID, 0, NULL, DEFAULT_SEQN,
916 IPMB_ADDR(dest), SMC_NETFN_APP_REQ, SMC_BMC_LUN);
918 if (smc_send_msg(DEFAULT_FD, &req_pkt, &res_pkt,
919 FRUID_CHECK_POLL_TIMEOUT) != SMC_SUCCESS) {
920 return (0);
922 return (1); /* got response */
926 is_fru_data_available(int precedence, int slot_no, format_t *fru_format)
928 int ret, fd = 0;
929 uint8_t data[TMP_BUFFER_SIZE];
931 fru_format->format = NO_FRUDATA;
932 if (fru_format->dest == 0x20) { /* alarm card */
933 ret = is_alarm_frudata_available(fru_format);
934 return (ret);
937 if (cpu_no == 0) { /* get the geo_addr */
938 sc_reqmsg_t req_pkt;
939 sc_rspmsg_t rsp_pkt;
940 uint8_t size = 0;
942 /* initialize the request packet */
943 (void) smc_init_smc_msg(&req_pkt,
944 SMC_GET_GEOGRAPHICAL_ADDRESS, DEFAULT_SEQN, size);
945 /* make a call to smc library to send cmd */
946 if (smc_send_msg(DEFAULT_FD, &req_pkt, &rsp_pkt,
947 POLL_TIMEOUT) != SMC_SUCCESS) {
948 return (0);
950 if (SC_MSG_LEN(&rsp_pkt) == 0) {
951 return (0);
953 cpu_no = rsp_pkt.data[0];
956 /* check if it is IPMI intelligent or not */
957 if (slot_no != cpu_no) {
958 ret = is_ipmi_capable(cpu_no, slot_no);
959 if (ret == 0) { /* dumb I/O card */
960 return (0);
964 /* check if ipmi frudata is present or not */
965 ret = is_ipmi_fru_data_available(cpu_no, slot_no);
966 if (ret == 1) {
967 fru_format->format |= IPMI_FORMAT;
968 fru_format->sun_device_id = 0x0;
969 fru_format->sun_lun = 0x0;
971 /* no need to look for sun format */
972 if (precedence == IPMI_FORMAT) {
973 return (fru_format->format);
977 /* check if sun fruid is present */
978 get_fru_data_info(cpu_no, slot_no, fru_format);
979 /* check the hdr version */
980 if (fru_format->format & SUN_FORMAT) {
981 ret = pread_new(fd, &data, BYTE_TO_READ_SUN_CHK,
982 STATIC_OFFSET, fru_format);
983 if (ret != BYTE_TO_READ_SUN_CHK) {
984 fru_format->format = fru_format->format &
985 (~ (SUN_FORMAT));
986 fru_format->sun_device_id = 0x0;
987 fru_format->sun_lun = 0x0;
989 if (data[0] != SECTION_HDR_TAG) {
990 fru_format->format = fru_format->format &
991 (~ (SUN_FORMAT));
992 fru_format->sun_device_id = 0x0;
993 fru_format->sun_lun = 0x0;
996 return (fru_format->format);