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, Version 1.0 only
6 * (the "License"). You may not use this file except in compliance
7 * with the License.
8 *
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.
13 *
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]
19 *
20 * CDDL HEADER END
21 */
22 /*
23 * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
25 */
26
27 #pragma ident "%Z%%M% %I% %E% SMI"
28
29 /*
30 * Read the SDR information on a board and get the device id to
31 * read the FRUID information
32 */
33
34 #include <stdio.h>
35 #include <sys/types.h>
36 #include <sys/stat.h>
37 #include <fcntl.h>
38 #include <errno.h>
39 #include <time.h>
40 #include <poll.h>
41 #include <stropts.h>
42 #include <stdarg.h>
43 #include <syslog.h>
44 #include <smclib.h>
45 #include "fru_access_impl.h"
46
47 #define POLL_TIMEOUT 10000 /* 20 sec */
48 #define SEQUENCE 10
49
50 #define IPMI_GET_SDR_INFO 0x20
51 #define IPMI_SENSOR_NETFN 0x4
52 #define SDR_INFO_RESPONSE_SZ_MIN 10
53
54 #define NUM_OF_LUN 4
55 #define SUN_FRU "SUN FRU SDR"
56 #define FRU_DEVICE_SDR_TYPE 0x11
57 #define IPMI_SDR_VERSION 0x51
58 #define IPMI_DATA_OFFSET 7
59 #define IPMI_GET_SDR_INFO_CMD 0x20
60 #define SDR_BUFFER_LEN_MAX 100
61
62 typedef struct {
63 uint8_t src;
64 uint8_t dest;
65 uint8_t lun;
66 uint8_t record_id_lsb;
67 uint8_t record_id_msb;
68 int offset;
69 int length;
70 char *buffer;
71 } sdr_info_t;
72
73 static int get_sdr_info(int, int, uint8_t lun);
74 static int get_sdr(sdr_info_t *);
75 static int get_sun_sdr(int, uint8_t, uint8_t, uint8_t);
76
77 /*
78 * bug in smc f/w
79 *
80 * static int lun_mask[4] = { 0x01, 0x02, 0x04, 0x08 };
81 */
82
83 /*
84 * routine to read the onboard/remote device SDR information
85 */
86 void
get_fru_data_info(int src,int dest,format_t * fru_format)87 get_fru_data_info(int src, int dest, format_t *fru_format)
88 {
89 int ret;
90
91 src = IPMB_ADDR(src);
92 dest = IPMB_ADDR(dest);
93
94 if (src != dest) { /* ipmi */
95 int i = 0;
96 for (i = 0; i < NUM_OF_LUN; i++) { /* for each lun */
97 ret = get_sdr_info(src, dest, i);
98 if (ret > 0) {
99 ret = get_sun_sdr(ret, src, dest, i);
100 if (ret > 0) {
101 fru_format->format |= SUN_FORMAT;
102 fru_format->sun_device_id = ret;
103 fru_format->sun_lun = i;
104 break;
105 }
106 }
107 }
108 } else { /* on board */
109 ret = get_sdr_info(src, dest, 0);
110 if (ret > 0) {
111 ret = get_sun_sdr(ret, src, dest, 0);
112 if (ret > 0) {
113 fru_format->format |= SUN_FORMAT;
114 fru_format->sun_device_id = ret;
115 fru_format->sun_lun = 0;
116 }
117 }
118 }
119 }
120
121 /*
122 * read the onboard sdr information
123 */
124 static int
get_onboard_sdr(sdr_info_t * sdr)125 get_onboard_sdr(sdr_info_t *sdr)
126 {
127 sc_reqmsg_t req_pkt;
128 sc_rspmsg_t res_pkt;
129
130 SC_MSG_CMD(&req_pkt) = SMC_DEVICE_SDR_GET;
131 SC_MSG_LEN(&req_pkt) = 6;
132 SC_MSG_ID(&req_pkt) = SEQUENCE;
133
134 /* data for request packet */
135 req_pkt.data[0] = 0x0;
136 req_pkt.data[1] = 0x0;
137 req_pkt.data[2] = sdr->record_id_lsb;
138 req_pkt.data[3] = sdr->record_id_msb;
139 req_pkt.data[4] = sdr->offset;
140 req_pkt.data[5] = sdr->length;
141
142 if (smc_send_msg(DEFAULT_FD, &req_pkt, &res_pkt,
143 POLL_TIMEOUT) != SMC_SUCCESS) {
144 return (-1);
145 }
146
147 bzero(sdr->buffer, SDR_BUFFER_LEN_MAX);
148 (void) memcpy(sdr->buffer, res_pkt.data, res_pkt.hdr.len);
149 return (0);
150 }
151
152 /*
153 * get the sdr information
154 */
155 static int
get_sdr_info(int src,int dest,uint8_t lun)156 get_sdr_info(int src, int dest, uint8_t lun)
157 {
158 sc_reqmsg_t req_pkt;
159 sc_rspmsg_t res_pkt;
160
161 if (lun >= NUM_OF_LUN) {
162 return (-1);
163 }
164
165 if (src == dest) { /* onboard */
166 SC_MSG_CMD(&req_pkt) = SMC_DEVICE_SDR_INFO_GET;
167 SC_MSG_LEN(&req_pkt) = 0;
168 SC_MSG_ID(&req_pkt) = SEQUENCE;
169 if (smc_send_msg(DEFAULT_FD, &req_pkt, &res_pkt,
170 POLL_TIMEOUT) != SMC_SUCCESS) {
171 return (-1);
172 }
173 return (res_pkt.data[0]);
174 }
175
176 /* ipmb access */
177 (void) smc_init_ipmi_msg(&req_pkt, IPMI_GET_SDR_INFO_CMD,
178 FRUACCESS_MSG_ID, 0, NULL, DEFAULT_SEQN, dest,
179 SMC_NETFN_SENSOR_REQ, lun);
180
181 if (smc_send_msg(DEFAULT_FD, &req_pkt, &res_pkt,
182 POLL_TIMEOUT) != SMC_SUCCESS) {
183 return (-1);
184 }
185
186 /* completion code */
187 if (res_pkt.data[IPMI_DATA_OFFSET] != 0) {
188 return (-1);
189 }
190
191 /*
192 * Known bug in SMC f/w. take this out for next release
193 * if ((res_pkt.data[IPMI_DATA_OFFSET + 2] & lun_mask[lun]) != 1) {
194 * return (0);
195 * }
196 */
197 return (res_pkt.data[IPMI_DATA_OFFSET + 1]);
198 }
199
200 static int
get_sun_sdr(int num_records,uint8_t src,uint8_t dest,uint8_t lun)201 get_sun_sdr(int num_records, uint8_t src, uint8_t dest, uint8_t lun)
202 {
203 int i, ret;
204 sdr_info_t sdr;
205 char data[SDR_BUFFER_LEN_MAX];
206 uint8_t next_record_lsb;
207 uint8_t next_record_msb;
208
209 sdr.src = src;
210 sdr.dest = dest;
211 sdr.lun = lun;
212 sdr.buffer = data;
213
214 /* get the first record info */
215 next_record_lsb = 0x0;
216 next_record_msb = 0x0;
217 sdr.length = 4;
218 sdr.offset = 0x0;
219
220 if (src == dest) { /* onboard */
221 for (i = 0; i < num_records; i++) {
222 sdr.record_id_lsb = next_record_lsb;
223 sdr.record_id_msb = next_record_msb;
224
225 if ((ret = get_onboard_sdr(&sdr)) < 0) {
226 return (ret);
227 }
228
229 next_record_lsb = data[0];
230 next_record_msb = data[1];
231 if (data[4] != IPMI_SDR_VERSION) {
232 return (-1);
233 }
234
235 if (data[5] == FRU_DEVICE_SDR_TYPE) {
236 sdr.offset = 0x10;
237 sdr.length = strlen(SUN_FRU);
238 if ((ret = get_onboard_sdr(&sdr)) < 0) {
239 return (ret);
240 }
241
242 /* first two bytes of response is reserv. id */
243 if (strncmp(SUN_FRU, &data[2],
244 strlen(SUN_FRU)) == 0) {
245 /* found sun sdr */
246 sdr.offset = 0x0;
247 sdr.length = 7;
248 if ((ret = get_onboard_sdr(&sdr)) < 0) {
249 return (ret);
250 }
251 return (data[8]);
252 }
253 }
254 }
255 return (-1);
256 }
257
258 /* ipmb access */
259 /* traverse thru all the records until we find sun sdr */
260 for (i = 0; i < num_records; i++) {
261
262 sdr.record_id_lsb = next_record_lsb;
263 sdr.record_id_msb = next_record_msb;
264
265 if ((ret = get_sdr(&sdr)) < 0) {
266 return (ret);
267 }
268
269 /* completion code */
270 if (data[IPMI_DATA_OFFSET] != 0) {
271 return (-1);
272 }
273 next_record_lsb = data[IPMI_DATA_OFFSET + 1];
274 next_record_msb = data[IPMI_DATA_OFFSET + 2];
275
276 if (data[IPMI_DATA_OFFSET + 5] != IPMI_SDR_VERSION) {
277 return (-1);
278 }
279
280 if (data[IPMI_DATA_OFFSET + 6] == FRU_DEVICE_SDR_TYPE) {
281
282 sdr.offset = 0x10;
283 sdr.length = strlen(SUN_FRU);
284 if ((ret = get_sdr(&sdr)) < 0) {
285 return (ret);
286 }
287
288 /* completion code */
289 if (data[IPMI_DATA_OFFSET] != 0) {
290 return (-1);
291 }
292
293 if (strncmp(&data[IPMI_DATA_OFFSET+ 3],
294 SUN_FRU, strlen(SUN_FRU)) == 0) {
295 /* found sun sdr */
296 sdr.offset = 0x0;
297 sdr.length = 7;
298 if ((ret = get_sdr(&sdr)) < 0) {
299 return (ret);
300 }
301
302 /* completion code */
303 if (data[IPMI_DATA_OFFSET] != 0) {
304 return (-1);
305 }
306 return (data[IPMI_DATA_OFFSET + 9]);
307 }
308 }
309 }
310 return (-1);
311 }
312
313 static int
get_sdr(sdr_info_t * sdr)314 get_sdr(sdr_info_t *sdr)
315 {
316 sc_reqmsg_t req_pkt;
317 sc_rspmsg_t res_pkt;
318 uint8_t datap[6];
319
320 if (sdr->lun > 3) {
321 return (-1);
322 }
323
324 /* data for request packet */
325 datap[0] = 0x0; /* reserved */
326 datap[1] = 0x0; /* reserved */
327 datap[2] = sdr->record_id_lsb;
328 datap[3] = sdr->record_id_msb;
329 datap[4] = sdr->offset;
330 datap[5] = sdr->length;
331
332 (void) smc_init_ipmi_msg(&req_pkt, SMC_GET_DEVICE_SDR,
333 FRUACCESS_MSG_ID, 6, datap, DEFAULT_SEQN,
334 sdr->dest, SMC_NETFN_SENSOR_REQ, sdr->lun);
335
336 if (smc_send_msg(DEFAULT_FD, &req_pkt, &res_pkt,
337 POLL_TIMEOUT) != SMC_SUCCESS) {
338 return (-1);
339 }
340 bzero(sdr->buffer, SDR_BUFFER_LEN_MAX);
341 (void) memcpy(sdr->buffer, res_pkt.data, res_pkt.hdr.len);
342 return (0);
343 }
344