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.
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.
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]
22 * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
26 #pragma ident "%Z%%M% %I% %E% SMI"
31 #include "ipmi_impl.h"
34 * Extracts bits between index h (high, inclusive) and l (low, exclusive) from
35 * u, which must be an unsigned integer.
37 #define BITX(u, h, l) (((u) >> (l)) & ((1LU << ((h) - (l) + 1LU)) - 1LU))
39 typedef struct ipmi_fru_read
42 uint8_t ifr_offset_lsb
;
43 uint8_t ifr_offset_msb
;
48 * returns: size of FRU inventory data in bytes, on success
52 ipmi_fru_read(ipmi_handle_t
*ihp
, ipmi_sdr_fru_locator_t
*fru_loc
, char **buf
)
54 ipmi_cmd_t cmd
, *resp
;
56 uint16_t sz
, offset
= 0;
57 ipmi_fru_read_t cmd_data_in
;
60 devid
= fru_loc
->_devid_or_slaveaddr
._logical
._is_fl_devid
;
62 * First we issue a command to retrieve the size of the specified FRU's
65 cmd
.ic_netfn
= IPMI_NETFN_STORAGE
;
66 cmd
.ic_cmd
= IPMI_CMD_GET_FRU_INV_AREA
;
68 cmd
.ic_dlen
= sizeof (uint8_t);
71 if ((resp
= ipmi_send(ihp
, &cmd
)) == NULL
)
74 if (resp
->ic_dlen
!= 3) {
75 (void) ipmi_set_error(ihp
, EIPMI_BAD_RESPONSE_LENGTH
, NULL
);
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
);
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
;
92 cmd_data_in
.ifr_count
= 128;
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
);
100 if ((resp
= ipmi_send(ihp
, &cmd
)) == NULL
) {
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
,
112 (void) memcpy(tmp
+offset
, (char *)(resp
->ic_data
)+1, count
);
120 ipmi_fru_parse_product(ipmi_handle_t
*ihp
, char *fru_area
,
121 ipmi_fru_prod_info_t
*buf
)
123 ipmi_fru_hdr_t fru_hdr
;
125 uint8_t len
, typelen
;
127 (void) memcpy(&fru_hdr
, fru_area
, sizeof (ipmi_fru_hdr_t
));
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.
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.
136 if (!fru_hdr
.ifh_product_info_off
) {
137 (void) ipmi_set_error(ihp
, EIPMI_NOT_PRESENT
, NULL
);
141 tmp
= fru_area
+ (fru_hdr
.ifh_product_info_off
* 8) + 3;
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
);
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
);
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
);
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
);
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
);
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
);
180 * The Board Info area is described in Sect 11 of the IPMI Platform Management
181 * FRU Information Storage Definition (v1.1).
184 ipmi_fru_parse_board(ipmi_handle_t
*ihp
, char *fru_area
,
185 ipmi_fru_brd_info_t
*buf
)
187 ipmi_fru_hdr_t fru_hdr
;
189 uint8_t len
, typelen
;
191 (void) memcpy(&fru_hdr
, fru_area
, sizeof (ipmi_fru_hdr_t
));
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.
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.
200 if (!fru_hdr
.ifh_board_info_off
) {
201 (void) ipmi_set_error(ihp
, EIPMI_NOT_PRESENT
, NULL
);
204 tmp
= fru_area
+ (fru_hdr
.ifh_board_info_off
* 8) + 3;
206 (void) memcpy(buf
->ifbi_manuf_date
, tmp
, 3);
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
);
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
);
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
);
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
);