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