Home | History | Annotate | Download | only in common
      1 /*
      2  * CDDL HEADER START
      3  *
      4  * The contents of this file are subject to the terms of the
      5  * Common Development and Distribution License (the "License").
      6  * You may not use this file except in compliance with the License.
      7  *
      8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
      9  * or http://www.opensolaris.org/os/licensing.
     10  * See the License for the specific language governing permissions
     11  * and limitations under the License.
     12  *
     13  * When distributing Covered Code, include this CDDL HEADER in each
     14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
     15  * If applicable, add the following below this CDDL HEADER, with the
     16  * fields enclosed by brackets "[]" replaced with your own identifying
     17  * information: Portions Copyright [yyyy] [name of copyright owner]
     18  *
     19  * CDDL HEADER END
     20  */
     21 /*
     22  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
     23  * Use is subject to license terms.
     24  */
     25 
     26 #pragma ident	"%Z%%M%	%I%	%E% SMI"
     27 
     28 #include <libipmi.h>
     29 #include <string.h>
     30 
     31 #include "ipmi_impl.h"
     32 
     33 /*
     34  * Extracts bits between index h (high, inclusive) and l (low, exclusive) from
     35  * u, which must be an unsigned integer.
     36  */
     37 #define	BITX(u, h, l)	(((u) >> (l)) & ((1LU << ((h) - (l) + 1LU)) - 1LU))
     38 
     39 typedef struct ipmi_fru_read
     40 {
     41 	uint8_t		ifr_devid;
     42 	uint8_t		ifr_offset_lsb;
     43 	uint8_t		ifr_offset_msb;
     44 	uint8_t		ifr_count;
     45 } ipmi_fru_read_t;
     46 
     47 /*
     48  * returns: size of FRU inventory data in bytes, on success
     49  *          -1, otherwise
     50  */
     51 int
     52 ipmi_fru_read(ipmi_handle_t *ihp, ipmi_sdr_fru_locator_t *fru_loc, char **buf)
     53 {
     54 	ipmi_cmd_t cmd, *resp;
     55 	uint8_t count, devid;
     56 	uint16_t sz, offset = 0;
     57 	ipmi_fru_read_t cmd_data_in;
     58 	char *tmp;
     59 
     60 	devid = fru_loc->_devid_or_slaveaddr._logical._is_fl_devid;
     61 	/*
     62 	 * First we issue a command to retrieve the size of the specified FRU's
     63 	 * inventory area
     64 	 */
     65 	cmd.ic_netfn = IPMI_NETFN_STORAGE;
     66 	cmd.ic_cmd = IPMI_CMD_GET_FRU_INV_AREA;
     67 	cmd.ic_data = &devid;
     68 	cmd.ic_dlen = sizeof (uint8_t);
     69 	cmd.ic_lun = 0;
     70 
     71 	if ((resp = ipmi_send(ihp, &cmd)) == NULL)
     72 		return (-1);
     73 
     74 	if (resp->ic_dlen != 3) {
     75 		(void) ipmi_set_error(ihp, EIPMI_BAD_RESPONSE_LENGTH, NULL);
     76 		return (-1);
     77 	}
     78 
     79 	(void) memcpy(&sz, resp->ic_data, sizeof (uint16_t));
     80 	if ((tmp = malloc(sz)) == NULL) {
     81 		(void) ipmi_set_error(ihp, EIPMI_NOMEM, NULL);
     82 		return (-1);
     83 	}
     84 
     85 	while (offset < sz) {
     86 		cmd_data_in.ifr_devid = devid;
     87 		cmd_data_in.ifr_offset_lsb = BITX(offset, 7, 0);
     88 		cmd_data_in.ifr_offset_msb = BITX(offset, 15, 8);
     89 		if ((sz - offset) < 128)
     90 			cmd_data_in.ifr_count = sz - offset;
     91 		else
     92 			cmd_data_in.ifr_count = 128;
     93 
     94 		cmd.ic_netfn = IPMI_NETFN_STORAGE;
     95 		cmd.ic_cmd = IPMI_CMD_READ_FRU_DATA;
     96 		cmd.ic_data = &cmd_data_in;
     97 		cmd.ic_dlen = sizeof (ipmi_fru_read_t);
     98 		cmd.ic_lun = 0;
     99 
    100 		if ((resp = ipmi_send(ihp, &cmd)) == NULL) {
    101 			free(tmp);
    102 			return (-1);
    103 		}
    104 
    105 		(void) memcpy(&count, resp->ic_data, sizeof (uint8_t));
    106 		if (count != cmd_data_in.ifr_count) {
    107 			(void) ipmi_set_error(ihp, EIPMI_BAD_RESPONSE_LENGTH,
    108 			    NULL);
    109 			free(tmp);
    110 			return (-1);
    111 		}
    112 		(void) memcpy(tmp+offset, (char *)(resp->ic_data)+1, count);
    113 		offset += count;
    114 	}
    115 	*buf = tmp;
    116 	return (sz);
    117 }
    118 
    119 int
    120 ipmi_fru_parse_product(ipmi_handle_t *ihp, char *fru_area,
    121     ipmi_fru_prod_info_t *buf)
    122 {
    123 	ipmi_fru_hdr_t fru_hdr;
    124 	char *tmp;
    125 	uint8_t len, typelen;
    126 
    127 	(void) memcpy(&fru_hdr, fru_area, sizeof (ipmi_fru_hdr_t));
    128 
    129 	/*
    130 	 * We get the offset to the product info area from the FRU common
    131 	 * header which is at the start of the FRU inventory area.
    132 	 *
    133 	 * The product info area is optional, so if the offset is NULL,
    134 	 * indicating that it doesn't exist, then we return an error.
    135 	 */
    136 	if (!fru_hdr.ifh_product_info_off) {
    137 		(void) ipmi_set_error(ihp, EIPMI_NOT_PRESENT, NULL);
    138 		return (-1);
    139 	}
    140 
    141 	tmp = fru_area + (fru_hdr.ifh_product_info_off * 8) + 3;
    142 
    143 	(void) memcpy(&typelen, tmp, sizeof (uint8_t));
    144 	len = BITX(typelen, 5, 0);
    145 	ipmi_decode_string((typelen >> 6), len, tmp+1, buf->ifpi_manuf_name);
    146 	tmp += len + 1;
    147 
    148 	(void) memcpy(&typelen, tmp, sizeof (uint8_t));
    149 	len = BITX(typelen, 5, 0);
    150 	ipmi_decode_string((typelen >> 6), len, tmp+1,
    151 	    buf->ifpi_product_name);
    152 	tmp += len + 1;
    153 
    154 	(void) memcpy(&typelen, tmp, sizeof (uint8_t));
    155 	len = BITX(typelen, 5, 0);
    156 	ipmi_decode_string((typelen >> 6), len, tmp+1, buf->ifpi_part_number);
    157 	tmp += len + 1;
    158 
    159 	(void) memcpy(&typelen, tmp, sizeof (uint8_t));
    160 	len = BITX(typelen, 5, 0);
    161 	ipmi_decode_string((typelen >> 6), len, tmp+1,
    162 	    buf->ifpi_product_version);
    163 	tmp += len + 1;
    164 
    165 	(void) memcpy(&typelen, tmp, sizeof (uint8_t));
    166 	len = BITX(typelen, 5, 0);
    167 	ipmi_decode_string((typelen >> 6), len, tmp+1,
    168 	    buf->ifpi_product_serial);
    169 	tmp += len + 1;
    170 
    171 	(void) memcpy(&typelen, tmp, sizeof (uint8_t));
    172 	len = BITX(typelen, 5, 0);
    173 	ipmi_decode_string((typelen >> 6), len, tmp+1, buf->ifpi_asset_tag);
    174 
    175 	return (0);
    176 }
    177 
    178 
    179 /*
    180  * The Board Info area is described in Sect 11 of the IPMI Platform Management
    181  * FRU Information Storage Definition (v1.1).
    182  */
    183 int
    184 ipmi_fru_parse_board(ipmi_handle_t *ihp, char *fru_area,
    185     ipmi_fru_brd_info_t *buf)
    186 {
    187 	ipmi_fru_hdr_t fru_hdr;
    188 	char *tmp;
    189 	uint8_t len, typelen;
    190 
    191 	(void) memcpy(&fru_hdr, fru_area, sizeof (ipmi_fru_hdr_t));
    192 
    193 	/*
    194 	 * We get the offset to the board info area from the FRU common
    195 	 * header which is at the start of the FRU inventory area.
    196 	 *
    197 	 * The board info area is optional, so if the offset is NULL,
    198 	 * indicating that it doesn't exist, then we return an error.
    199 	 */
    200 	if (!fru_hdr.ifh_board_info_off) {
    201 		(void) ipmi_set_error(ihp, EIPMI_NOT_PRESENT, NULL);
    202 		return (-1);
    203 	}
    204 	tmp = fru_area + (fru_hdr.ifh_board_info_off * 8) + 3;
    205 
    206 	(void) memcpy(buf->ifbi_manuf_date, tmp, 3);
    207 	tmp += 3;
    208 
    209 	(void) memcpy(&typelen, tmp, sizeof (uint8_t));
    210 	len = BITX(typelen, 5, 0);
    211 	ipmi_decode_string((typelen >> 6), len, tmp+1, buf->ifbi_manuf_name);
    212 	tmp += len + 1;
    213 
    214 	(void) memcpy(&typelen, tmp, sizeof (uint8_t));
    215 	len = BITX(typelen, 5, 0);
    216 	ipmi_decode_string((typelen >> 6), len, tmp+1, buf->ifbi_board_name);
    217 	tmp += len + 1;
    218 
    219 	(void) memcpy(&typelen, tmp, sizeof (uint8_t));
    220 	len = BITX(typelen, 5, 0);
    221 	ipmi_decode_string((typelen >> 6), len, tmp+1,
    222 	    buf->ifbi_product_serial);
    223 	tmp += len + 1;
    224 
    225 	(void) memcpy(&typelen, tmp, sizeof (uint8_t));
    226 	len = BITX(typelen, 5, 0);
    227 	ipmi_decode_string((typelen >> 6), len, tmp+1, buf->ifbi_part_number);
    228 
    229 	return (0);
    230 }
    231