xref: /titanic_50/usr/src/cmd/picl/plugins/sun4u/snowbird/lib/fruaccess/piclsdr.c (revision 7c478bd95313f5f23a4c958a745db2134aa03244)
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