xref: /titanic_44/usr/src/lib/libipmi/common/ipmi_fru.c (revision 2cb5535af222653abf2eba5c180ded4a7b85d8b6)
14557a2a1Srobj /*
24557a2a1Srobj  * CDDL HEADER START
34557a2a1Srobj  *
44557a2a1Srobj  * The contents of this file are subject to the terms of the
54557a2a1Srobj  * Common Development and Distribution License (the "License").
64557a2a1Srobj  * You may not use this file except in compliance with the License.
74557a2a1Srobj  *
84557a2a1Srobj  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
94557a2a1Srobj  * or http://www.opensolaris.org/os/licensing.
104557a2a1Srobj  * See the License for the specific language governing permissions
114557a2a1Srobj  * and limitations under the License.
124557a2a1Srobj  *
134557a2a1Srobj  * When distributing Covered Code, include this CDDL HEADER in each
144557a2a1Srobj  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
154557a2a1Srobj  * If applicable, add the following below this CDDL HEADER, with the
164557a2a1Srobj  * fields enclosed by brackets "[]" replaced with your own identifying
174557a2a1Srobj  * information: Portions Copyright [yyyy] [name of copyright owner]
184557a2a1Srobj  *
194557a2a1Srobj  * CDDL HEADER END
204557a2a1Srobj  */
214557a2a1Srobj /*
222eeaed14Srobj  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
234557a2a1Srobj  * Use is subject to license terms.
244557a2a1Srobj  */
254557a2a1Srobj 
264557a2a1Srobj #pragma ident	"%Z%%M%	%I%	%E% SMI"
274557a2a1Srobj 
284557a2a1Srobj #include <libipmi.h>
294557a2a1Srobj #include <string.h>
304557a2a1Srobj 
314557a2a1Srobj #include "ipmi_impl.h"
324557a2a1Srobj 
334557a2a1Srobj /*
344557a2a1Srobj  * Extracts bits between index h (high, inclusive) and l (low, exclusive) from
354557a2a1Srobj  * u, which must be an unsigned integer.
364557a2a1Srobj  */
374557a2a1Srobj #define	BITX(u, h, l)	(((u) >> (l)) & ((1LU << ((h) - (l) + 1LU)) - 1LU))
384557a2a1Srobj 
394557a2a1Srobj typedef struct ipmi_fru_read
404557a2a1Srobj {
414557a2a1Srobj 	uint8_t		ifr_devid;
424557a2a1Srobj 	uint8_t		ifr_offset_lsb;
434557a2a1Srobj 	uint8_t		ifr_offset_msb;
444557a2a1Srobj 	uint8_t		ifr_count;
454557a2a1Srobj } ipmi_fru_read_t;
464557a2a1Srobj 
474557a2a1Srobj /*
484557a2a1Srobj  * returns: size of FRU inventory data in bytes, on success
494557a2a1Srobj  *          -1, otherwise
504557a2a1Srobj  */
514557a2a1Srobj int
ipmi_fru_read(ipmi_handle_t * ihp,ipmi_sdr_fru_locator_t * fru_loc,char ** buf)524557a2a1Srobj ipmi_fru_read(ipmi_handle_t *ihp, ipmi_sdr_fru_locator_t *fru_loc, char **buf)
534557a2a1Srobj {
544557a2a1Srobj 	ipmi_cmd_t cmd, *resp;
554557a2a1Srobj 	uint8_t count, devid;
564557a2a1Srobj 	uint16_t sz, offset = 0;
574557a2a1Srobj 	ipmi_fru_read_t cmd_data_in;
58*2cb5535aSrobj 	char *tmp;
594557a2a1Srobj 
604557a2a1Srobj 	devid = fru_loc->_devid_or_slaveaddr._logical._is_fl_devid;
614557a2a1Srobj 	/*
624557a2a1Srobj 	 * First we issue a command to retrieve the size of the specified FRU's
634557a2a1Srobj 	 * inventory area
644557a2a1Srobj 	 */
654557a2a1Srobj 	cmd.ic_netfn = IPMI_NETFN_STORAGE;
664557a2a1Srobj 	cmd.ic_cmd = IPMI_CMD_GET_FRU_INV_AREA;
674557a2a1Srobj 	cmd.ic_data = &devid;
684557a2a1Srobj 	cmd.ic_dlen = sizeof (uint8_t);
694557a2a1Srobj 	cmd.ic_lun = 0;
704557a2a1Srobj 
714557a2a1Srobj 	if ((resp = ipmi_send(ihp, &cmd)) == NULL)
724557a2a1Srobj 		return (-1);
734557a2a1Srobj 
744557a2a1Srobj 	if (resp->ic_dlen != 3) {
754557a2a1Srobj 		(void) ipmi_set_error(ihp, EIPMI_BAD_RESPONSE_LENGTH, NULL);
764557a2a1Srobj 		return (-1);
774557a2a1Srobj 	}
784557a2a1Srobj 
794557a2a1Srobj 	(void) memcpy(&sz, resp->ic_data, sizeof (uint16_t));
80*2cb5535aSrobj 	if ((tmp = malloc(sz)) == NULL) {
814557a2a1Srobj 		(void) ipmi_set_error(ihp, EIPMI_NOMEM, NULL);
824557a2a1Srobj 		return (-1);
834557a2a1Srobj 	}
844557a2a1Srobj 
854557a2a1Srobj 	while (offset < sz) {
864557a2a1Srobj 		cmd_data_in.ifr_devid = devid;
874557a2a1Srobj 		cmd_data_in.ifr_offset_lsb = BITX(offset, 7, 0);
884557a2a1Srobj 		cmd_data_in.ifr_offset_msb = BITX(offset, 15, 8);
894557a2a1Srobj 		if ((sz - offset) < 128)
904557a2a1Srobj 			cmd_data_in.ifr_count = sz - offset;
914557a2a1Srobj 		else
924557a2a1Srobj 			cmd_data_in.ifr_count = 128;
934557a2a1Srobj 
944557a2a1Srobj 		cmd.ic_netfn = IPMI_NETFN_STORAGE;
954557a2a1Srobj 		cmd.ic_cmd = IPMI_CMD_READ_FRU_DATA;
964557a2a1Srobj 		cmd.ic_data = &cmd_data_in;
974557a2a1Srobj 		cmd.ic_dlen = sizeof (ipmi_fru_read_t);
984557a2a1Srobj 		cmd.ic_lun = 0;
994557a2a1Srobj 
100*2cb5535aSrobj 		if ((resp = ipmi_send(ihp, &cmd)) == NULL) {
101*2cb5535aSrobj 			free(tmp);
1024557a2a1Srobj 			return (-1);
103*2cb5535aSrobj 		}
1044557a2a1Srobj 
1054557a2a1Srobj 		(void) memcpy(&count, resp->ic_data, sizeof (uint8_t));
1064557a2a1Srobj 		if (count != cmd_data_in.ifr_count) {
1074557a2a1Srobj 			(void) ipmi_set_error(ihp, EIPMI_BAD_RESPONSE_LENGTH,
1084557a2a1Srobj 			    NULL);
109*2cb5535aSrobj 			free(tmp);
1104557a2a1Srobj 			return (-1);
1114557a2a1Srobj 		}
112*2cb5535aSrobj 		(void) memcpy(tmp+offset, (char *)(resp->ic_data)+1, count);
1134557a2a1Srobj 		offset += count;
1144557a2a1Srobj 	}
115*2cb5535aSrobj 	*buf = tmp;
1164557a2a1Srobj 	return (sz);
1174557a2a1Srobj }
1184557a2a1Srobj 
1194557a2a1Srobj int
ipmi_fru_parse_product(ipmi_handle_t * ihp,char * fru_area,ipmi_fru_prod_info_t * buf)1204557a2a1Srobj ipmi_fru_parse_product(ipmi_handle_t *ihp, char *fru_area,
1214557a2a1Srobj     ipmi_fru_prod_info_t *buf)
1224557a2a1Srobj {
1234557a2a1Srobj 	ipmi_fru_hdr_t fru_hdr;
1244557a2a1Srobj 	char *tmp;
1254557a2a1Srobj 	uint8_t len, typelen;
1264557a2a1Srobj 
1274557a2a1Srobj 	(void) memcpy(&fru_hdr, fru_area, sizeof (ipmi_fru_hdr_t));
1284557a2a1Srobj 
1294557a2a1Srobj 	/*
1304557a2a1Srobj 	 * We get the offset to the product info area from the FRU common
1314557a2a1Srobj 	 * header which is at the start of the FRU inventory area.
1324557a2a1Srobj 	 *
1334557a2a1Srobj 	 * The product info area is optional, so if the offset is NULL,
1344557a2a1Srobj 	 * indicating that it doesn't exist, then we return an error.
1354557a2a1Srobj 	 */
1364557a2a1Srobj 	if (!fru_hdr.ifh_product_info_off) {
1374557a2a1Srobj 		(void) ipmi_set_error(ihp, EIPMI_NOT_PRESENT, NULL);
1384557a2a1Srobj 		return (-1);
1394557a2a1Srobj 	}
1404557a2a1Srobj 
1414557a2a1Srobj 	tmp = fru_area + (fru_hdr.ifh_product_info_off * 8) + 3;
1424557a2a1Srobj 
1434557a2a1Srobj 	(void) memcpy(&typelen, tmp, sizeof (uint8_t));
144*2cb5535aSrobj 	len = BITX(typelen, 5, 0);
1452eeaed14Srobj 	ipmi_decode_string((typelen >> 6), len, tmp+1, buf->ifpi_manuf_name);
1464557a2a1Srobj 	tmp += len + 1;
1474557a2a1Srobj 
1484557a2a1Srobj 	(void) memcpy(&typelen, tmp, sizeof (uint8_t));
149*2cb5535aSrobj 	len = BITX(typelen, 5, 0);
1502eeaed14Srobj 	ipmi_decode_string((typelen >> 6), len, tmp+1,
1512eeaed14Srobj 	    buf->ifpi_product_name);
1524557a2a1Srobj 	tmp += len + 1;
1534557a2a1Srobj 
1544557a2a1Srobj 	(void) memcpy(&typelen, tmp, sizeof (uint8_t));
155*2cb5535aSrobj 	len = BITX(typelen, 5, 0);
1562eeaed14Srobj 	ipmi_decode_string((typelen >> 6), len, tmp+1, buf->ifpi_part_number);
1574557a2a1Srobj 	tmp += len + 1;
1584557a2a1Srobj 
1594557a2a1Srobj 	(void) memcpy(&typelen, tmp, sizeof (uint8_t));
160*2cb5535aSrobj 	len = BITX(typelen, 5, 0);
1612eeaed14Srobj 	ipmi_decode_string((typelen >> 6), len, tmp+1,
1622eeaed14Srobj 	    buf->ifpi_product_version);
1634557a2a1Srobj 	tmp += len + 1;
1644557a2a1Srobj 
1654557a2a1Srobj 	(void) memcpy(&typelen, tmp, sizeof (uint8_t));
166*2cb5535aSrobj 	len = BITX(typelen, 5, 0);
1672eeaed14Srobj 	ipmi_decode_string((typelen >> 6), len, tmp+1,
1682eeaed14Srobj 	    buf->ifpi_product_serial);
1694557a2a1Srobj 	tmp += len + 1;
1704557a2a1Srobj 
1714557a2a1Srobj 	(void) memcpy(&typelen, tmp, sizeof (uint8_t));
172*2cb5535aSrobj 	len = BITX(typelen, 5, 0);
1732eeaed14Srobj 	ipmi_decode_string((typelen >> 6), len, tmp+1, buf->ifpi_asset_tag);
1744557a2a1Srobj 
1754557a2a1Srobj 	return (0);
1764557a2a1Srobj }
1774557a2a1Srobj 
1784557a2a1Srobj 
1794557a2a1Srobj /*
1804557a2a1Srobj  * The Board Info area is described in Sect 11 of the IPMI Platform Management
1814557a2a1Srobj  * FRU Information Storage Definition (v1.1).
1824557a2a1Srobj  */
1834557a2a1Srobj int
ipmi_fru_parse_board(ipmi_handle_t * ihp,char * fru_area,ipmi_fru_brd_info_t * buf)1844557a2a1Srobj ipmi_fru_parse_board(ipmi_handle_t *ihp, char *fru_area,
1854557a2a1Srobj     ipmi_fru_brd_info_t *buf)
1864557a2a1Srobj {
1874557a2a1Srobj 	ipmi_fru_hdr_t fru_hdr;
1884557a2a1Srobj 	char *tmp;
1894557a2a1Srobj 	uint8_t len, typelen;
1904557a2a1Srobj 
1914557a2a1Srobj 	(void) memcpy(&fru_hdr, fru_area, sizeof (ipmi_fru_hdr_t));
1924557a2a1Srobj 
1934557a2a1Srobj 	/*
1944557a2a1Srobj 	 * We get the offset to the board info area from the FRU common
1954557a2a1Srobj 	 * header which is at the start of the FRU inventory area.
1964557a2a1Srobj 	 *
1974557a2a1Srobj 	 * The board info area is optional, so if the offset is NULL,
1984557a2a1Srobj 	 * indicating that it doesn't exist, then we return an error.
1994557a2a1Srobj 	 */
2004557a2a1Srobj 	if (!fru_hdr.ifh_board_info_off) {
2014557a2a1Srobj 		(void) ipmi_set_error(ihp, EIPMI_NOT_PRESENT, NULL);
2024557a2a1Srobj 		return (-1);
2034557a2a1Srobj 	}
2044557a2a1Srobj 	tmp = fru_area + (fru_hdr.ifh_board_info_off * 8) + 3;
2054557a2a1Srobj 
2064557a2a1Srobj 	(void) memcpy(buf->ifbi_manuf_date, tmp, 3);
2074557a2a1Srobj 	tmp += 3;
2084557a2a1Srobj 
2094557a2a1Srobj 	(void) memcpy(&typelen, tmp, sizeof (uint8_t));
210*2cb5535aSrobj 	len = BITX(typelen, 5, 0);
2112eeaed14Srobj 	ipmi_decode_string((typelen >> 6), len, tmp+1, buf->ifbi_manuf_name);
2124557a2a1Srobj 	tmp += len + 1;
2134557a2a1Srobj 
2144557a2a1Srobj 	(void) memcpy(&typelen, tmp, sizeof (uint8_t));
215*2cb5535aSrobj 	len = BITX(typelen, 5, 0);
2162eeaed14Srobj 	ipmi_decode_string((typelen >> 6), len, tmp+1, buf->ifbi_board_name);
2174557a2a1Srobj 	tmp += len + 1;
2184557a2a1Srobj 
2194557a2a1Srobj 	(void) memcpy(&typelen, tmp, sizeof (uint8_t));
220*2cb5535aSrobj 	len = BITX(typelen, 5, 0);
2212eeaed14Srobj 	ipmi_decode_string((typelen >> 6), len, tmp+1,
2222eeaed14Srobj 	    buf->ifbi_product_serial);
2234557a2a1Srobj 	tmp += len + 1;
2244557a2a1Srobj 
2254557a2a1Srobj 	(void) memcpy(&typelen, tmp, sizeof (uint8_t));
226*2cb5535aSrobj 	len = BITX(typelen, 5, 0);
2272eeaed14Srobj 	ipmi_decode_string((typelen >> 6), len, tmp+1, buf->ifbi_part_number);
2284557a2a1Srobj 
2294557a2a1Srobj 	return (0);
2304557a2a1Srobj }
231