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 /*
23 * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
25 */
26
27 #include <stdio.h>
28 #include <errno.h>
29 #include <fcntl.h>
30 #include <unistd.h>
31 #include <stdlib.h>
32 #include <stdarg.h>
33 #include <strings.h>
34 #include <limits.h>
35 #include <syslog.h>
36 #include <sys/open.h>
37 #include <string.h>
38 #include <alloca.h>
39 #include <libintl.h>
40 #include <sys/stat.h>
41 #include <sys/systeminfo.h>
42 #include <picl.h>
43 #include <picltree.h>
44 #include <fru_access.h>
45 #include <sys/sgfrutree.h>
46
47 /*
48 * these functions will overlay the symbol table of libfruaccess
49 * at runtime
50 */
51 container_hdl_t fru_open_container(picl_nodehdl_t fru);
52 int fru_close_container(container_hdl_t fru);
53 int fru_get_num_sections(container_hdl_t container,
54 door_cred_t *cred);
55 int fru_get_sections(container_hdl_t container, section_t *section,
56 int max_sections, door_cred_t *cred);
57 int fru_get_num_segments(section_hdl_t section, door_cred_t *cred);
58 int fru_get_segments(section_hdl_t section, segment_t *segment,
59 int max_segments, door_cred_t *cred);
60 int fru_add_segment(section_hdl_t section, segment_t *segment,
61 section_hdl_t *newsection, door_cred_t *cred);
62 int fru_delete_segment(segment_hdl_t segment,
63 section_hdl_t *newsection, door_cred_t *cred);
64 ssize_t fru_read_segment(segment_hdl_t segment, void *buffer,
65 size_t nbytes, door_cred_t *cred);
66 ssize_t fru_write_segment(segment_hdl_t segment, const void *data,
67 size_t nbytes, segment_hdl_t *newsegment,
68 door_cred_t *cred);
69 int fru_get_num_packets(segment_hdl_t segment, door_cred_t *cred);
70 int fru_get_packets(segment_hdl_t segment, packet_t *packet,
71 int max_packets, door_cred_t *cred);
72 int fru_update_payload(packet_hdl_t packet, const void *data,
73 size_t nbytes, packet_hdl_t *newpacket, door_cred_t *cred);
74 int fru_append_packet(segment_hdl_t segment, packet_t *packet,
75 const void *payload, size_t nbytes,
76 segment_hdl_t *newsegment, door_cred_t *cred);
77 int fru_delete_packet(packet_hdl_t packet,
78 segment_hdl_t *newsegment, door_cred_t *cred);
79 int fru_is_data_available(picl_nodehdl_t fru);
80
81 #define PICL_PROP_SC_HANDLE "SC_handle"
82 #define PICL_PROP_DATA_AVAIL "FRUDataAvailable"
83 #define MAX_LINE_SIZE 1024
84
85 #define OPENDEVFRU gettext("fru_open_dev: open of %s failed %s")
86 #define GETPV gettext("fru_open_container: ptree_get_propval_by_name failed %s")
87
88 static int
fru_open_dev(void)89 fru_open_dev(void)
90 {
91 static int opendevfru = 0;
92 static int frufd = 0;
93
94 if ((opendevfru == 0) && (frufd == 0)) {
95 if ((frufd = open(FRU_PSEUDO_DEV, O_RDWR, access)) == -1) {
96 syslog(LOG_ERR, OPENDEVFRU, FRU_PSEUDO_DEV,
97 strerror(errno));
98 return (-1);
99 }
100 opendevfru = 1;
101 }
102 return (frufd);
103 }
104
105 /*
106 * Look up the container_hdl in the PICL tree.
107 */
108 container_hdl_t
fru_open_container(picl_nodehdl_t fruh)109 fru_open_container(picl_nodehdl_t fruh)
110 {
111 int err;
112 container_hdl_t container_hdl;
113
114 if (fru_open_dev() == -1) {
115 return (0);
116 }
117
118 err = ptree_get_propval_by_name(fruh, PICL_PROP_DATA_AVAIL, NULL, 0);
119 if (err != PICL_SUCCESS) {
120 syslog(LOG_ERR, GETPV, PICL_PROP_DATA_AVAIL, err);
121 return (0);
122 }
123 err = ptree_get_propval_by_name(fruh, PICL_PROP_SC_HANDLE,
124 &container_hdl, sizeof (container_hdl_t));
125 if (err != PICL_SUCCESS) {
126 syslog(LOG_ERR, GETPV, PICL_PROP_SC_HANDLE, err);
127 return (0);
128 }
129 return (container_hdl);
130 }
131
132 /*
133 * Note : fru_open_container and fru_close_container do not map onto the opens
134 * and closes of the sgfru device on lw8. There is one sgfru device which
135 * handles all containers.
136 */
137 /*ARGSUSED*/
138 int
fru_close_container(container_hdl_t fru)139 fru_close_container(container_hdl_t fru)
140 {
141 if (fru_open_dev() == -1) {
142 return (-1);
143 }
144 return (0);
145 }
146
147 /*ARGSUSED*/
148 int
fru_get_num_sections(container_hdl_t container,door_cred_t * cred)149 fru_get_num_sections(container_hdl_t container, door_cred_t *cred)
150 {
151 section_info_t numsections;
152 int fd;
153
154 if ((fd = fru_open_dev()) == -1) {
155 return (-1);
156 }
157 numsections.hdl = container;
158 numsections.cnt = 0;
159 if (ioctl(fd, SGFRU_GETNUMSECTIONS, &numsections) != 0) {
160 return (-1);
161 }
162 return (numsections.cnt);
163 }
164
165 /*ARGSUSED*/
166 int
fru_get_sections(container_hdl_t container,section_t * section,int max_sections,door_cred_t * cred)167 fru_get_sections(container_hdl_t container, section_t *section,
168 int max_sections, door_cred_t *cred)
169 {
170 sections_t sections;
171 int fd;
172
173 if ((fd = fru_open_dev()) == -1) {
174 return (-1);
175 }
176 sections.fru_hdl = container;
177 sections.fru_cnt = max_sections;
178 sections.frus = section;
179 if (ioctl(fd, SGFRU_GETSECTIONS, §ions) != 0) {
180 return (-1);
181 }
182 return (sections.fru_cnt);
183 }
184
185 /*ARGSUSED*/
186 int
fru_get_num_segments(section_hdl_t section,door_cred_t * cred)187 fru_get_num_segments(section_hdl_t section, door_cred_t *cred)
188 {
189 segment_info_t numsegments;
190 int fd;
191
192 if ((fd = fru_open_dev()) == -1) {
193 return (-1);
194 }
195 numsegments.hdl = section;
196 numsegments.cnt = 0;
197 if (ioctl(fd, SGFRU_GETNUMSEGMENTS, &numsegments) != 0) {
198 return (-1);
199 }
200 return (numsegments.cnt);
201 }
202
203 /*ARGSUSED*/
204 int
fru_get_segments(section_hdl_t section,segment_t * segment,int max_segments,door_cred_t * cred)205 fru_get_segments(section_hdl_t section, segment_t *segment, int max_segments,
206 door_cred_t *cred)
207 {
208 segments_t segments;
209 int fd;
210
211 if ((fd = fru_open_dev()) == -1) {
212 return (-1);
213 }
214 segments.fru_hdl = section;
215 segments.fru_cnt = max_segments;
216 segments.frus = segment;
217 if (ioctl(fd, SGFRU_GETSEGMENTS, &segments) != 0) {
218 return (-1);
219 }
220 return (segments.fru_cnt);
221 }
222
223 /*ARGSUSED*/
224 int
fru_add_segment(section_hdl_t section,segment_t * segment,section_hdl_t * newsection,door_cred_t * cred)225 fru_add_segment(section_hdl_t section, segment_t *segment,
226 section_hdl_t *newsection, door_cred_t *cred)
227 {
228 segments_t newsegment;
229 int fd;
230
231 /* check the effective uid of the client */
232 if (cred->dc_euid != 0) {
233 errno = EPERM;
234 return (-1); /* not a root */
235 }
236
237 if ((fd = fru_open_dev()) == -1) {
238 return (-1);
239 }
240 newsegment.fru_hdl = section;
241 newsegment.fru_cnt = 1;
242 newsegment.frus = segment;
243 if (ioctl(fd, SGFRU_ADDSEGMENT, &newsegment) != 0) {
244 return (-1);
245 }
246 /*
247 * The new segment handle is returned in segment,
248 * return the updated section handle in newsection.
249 */
250 *newsection = newsegment.fru_hdl;
251 return (0);
252 }
253
254 int
fru_delete_segment(segment_hdl_t segment,section_hdl_t * newsection,door_cred_t * cred)255 fru_delete_segment(segment_hdl_t segment, section_hdl_t *newsection,
256 door_cred_t *cred)
257 {
258 segment_info_t delsegment;
259 int fd;
260
261 /* check the effective uid of the client */
262 if (cred->dc_euid != 0) {
263 errno = EPERM;
264 return (-1); /* not a root */
265 }
266
267 if ((fd = fru_open_dev()) == -1) {
268 return (-1);
269 }
270 delsegment.hdl = segment;
271 if (ioctl(fd, SGFRU_DELETESEGMENT, &delsegment) != 0) {
272 return (-1);
273 }
274 /* Return the updated section handle in newsection. */
275 *newsection = delsegment.hdl;
276 return (0);
277 }
278
279 /*ARGSUSED*/
280 ssize_t
fru_read_segment(segment_hdl_t segment,void * buffer,size_t nbytes,door_cred_t * cred)281 fru_read_segment(segment_hdl_t segment, void *buffer, size_t nbytes,
282 door_cred_t *cred)
283 {
284 segments_t readsegment;
285 int fd;
286
287 if ((fd = fru_open_dev()) == -1) {
288 return (-1);
289 }
290 readsegment.fru_hdl = segment;
291 readsegment.fru_cnt = nbytes;
292 readsegment.frus = buffer;
293 if (ioctl(fd, SGFRU_READRAWSEGMENT, &readsegment) != 0) {
294 return (-1);
295 }
296 return ((ssize_t)readsegment.fru_cnt);
297 }
298
299 /*ARGSUSED*/
300 ssize_t
fru_write_segment(segment_hdl_t segment,const void * buffer,size_t nbytes,segment_hdl_t * newsegment,door_cred_t * cred)301 fru_write_segment(segment_hdl_t segment, const void *buffer, size_t nbytes,
302 segment_hdl_t *newsegment, door_cred_t *cred)
303 {
304 segments_t writesegment;
305 int fd;
306
307 if ((fd = fru_open_dev()) == -1) {
308 return (-1);
309 }
310 writesegment.fru_hdl = segment;
311 writesegment.fru_cnt = nbytes;
312 writesegment.frus = (void *)buffer;
313 if (ioctl(fd, SGFRU_WRITERAWSEGMENT, &writesegment) != 0) {
314 return (-1);
315 }
316 /* Return the updated segment handle in newsegment. */
317 *newsegment = writesegment.fru_hdl;
318 return ((ssize_t)writesegment.fru_cnt);
319 }
320
321 /*ARGSUSED*/
322 int
fru_get_num_packets(segment_hdl_t segment,door_cred_t * cred)323 fru_get_num_packets(segment_hdl_t segment, door_cred_t *cred)
324 {
325 packet_info_t numpackets;
326 int fd;
327
328 if ((fd = fru_open_dev()) == -1) {
329 return (-1);
330 }
331 numpackets.hdl = segment;
332 numpackets.cnt = 0;
333 if (ioctl(fd, SGFRU_GETNUMPACKETS, &numpackets) != 0) {
334 return (-1);
335 }
336 return (numpackets.cnt);
337 }
338
339 /*ARGSUSED*/
340 int
fru_get_packets(segment_hdl_t segment,packet_t * packet,int max_packets,door_cred_t * cred)341 fru_get_packets(segment_hdl_t segment, packet_t *packet, int max_packets,
342 door_cred_t *cred)
343 {
344 packets_t packets;
345 int fd;
346
347 if ((fd = fru_open_dev()) == -1) {
348 return (-1);
349 }
350 packets.fru_hdl = segment;
351 packets.fru_cnt = max_packets;
352 packets.frus = packet;
353 if (ioctl(fd, SGFRU_GETPACKETS, &packets) != 0) {
354 return (-1);
355 }
356 return (packets.fru_cnt);
357 }
358
359 /*ARGSUSED*/
360 ssize_t
fru_get_payload(packet_hdl_t packet,void * buffer,size_t nbytes,door_cred_t * cred)361 fru_get_payload(packet_hdl_t packet, void *buffer, size_t nbytes,
362 door_cred_t *cred)
363 {
364 payload_t payload;
365 int fd;
366
367 if ((fd = fru_open_dev()) == -1) {
368 return (-1);
369 }
370 payload.fru_hdl = packet;
371 payload.fru_cnt = nbytes;
372 payload.frus = buffer;
373 if (ioctl(fd, SGFRU_GETPAYLOAD, &payload) != 0) {
374 return (-1);
375 }
376 return ((ssize_t)payload.fru_cnt);
377 }
378
379 int
fru_update_payload(packet_hdl_t packet,const void * data,size_t nbytes,packet_hdl_t * newpacket,door_cred_t * cred)380 fru_update_payload(packet_hdl_t packet, const void *data, size_t nbytes,
381 packet_hdl_t *newpacket, door_cred_t *cred)
382 {
383 payload_t payload;
384 int fd;
385
386 /* check the effective uid of the client */
387 if (cred->dc_euid != 0) {
388 errno = EPERM;
389 return (-1); /* not a root */
390 }
391
392 if ((fd = fru_open_dev()) == -1) {
393 return (-1);
394 }
395 payload.fru_hdl = packet;
396 payload.fru_cnt = nbytes;
397 payload.frus = (void *)data;
398 if (ioctl(fd, SGFRU_UPDATEPAYLOAD, &payload) != 0) {
399 return (-1);
400 }
401 /* Return the updated packet handle in newpacket. */
402 *newpacket = payload.fru_hdl;
403 return (0);
404 }
405
406 int
fru_append_packet(segment_hdl_t segment,packet_t * packet,const void * payload,size_t nbytes,segment_hdl_t * newsegment,door_cred_t * cred)407 fru_append_packet(segment_hdl_t segment, packet_t *packet, const void *payload,
408 size_t nbytes, segment_hdl_t *newsegment, door_cred_t *cred)
409 {
410 append_info_t appendpkt;
411 int fd;
412
413 /* check the effective uid of the client */
414 if (cred->dc_euid != 0) {
415 errno = EPERM;
416 return (-1); /* not a root */
417 }
418
419 if ((fd = fru_open_dev()) == -1) {
420 return (-1);
421 }
422 appendpkt.packet = *packet;
423 appendpkt.payload_hdl = segment;
424 appendpkt.payload_cnt = nbytes;
425 appendpkt.payload_data = (void *)payload;
426 if (ioctl(fd, SGFRU_APPENDPACKET, &appendpkt) != 0) {
427 return (-1);
428 }
429 /*
430 * The new packet handle is returned in packet,
431 * return the updated segment handle in newsegment.
432 */
433 packet->handle = appendpkt.packet.handle;
434 *newsegment = appendpkt.payload_hdl;
435 return (0);
436 }
437
438 int
fru_delete_packet(packet_hdl_t packet,segment_hdl_t * newsegment,door_cred_t * cred)439 fru_delete_packet(packet_hdl_t packet, segment_hdl_t *newsegment,
440 door_cred_t *cred)
441 {
442 packet_info_t delpacket;
443 int fd;
444
445 /* check the effective uid of the client */
446 if (cred->dc_euid != 0) {
447 errno = EPERM;
448 return (-1); /* not a root */
449 }
450
451 if ((fd = fru_open_dev()) == -1) {
452 return (-1);
453 }
454 delpacket.hdl = packet;
455 if (ioctl(fd, SGFRU_DELETEPACKET, &delpacket) != 0) {
456 return (-1);
457 }
458 /* Return the updated segment handle in newsegment. */
459 *newsegment = delpacket.hdl;
460 return (0);
461 }
462
463 /*
464 * Description :
465 * fru_is_data_available() checks to see if the frudata
466 * is available on a fru.
467 *
468 * Arguments :
469 * picl_nodehdl_t holds the picl node handle of the fru.
470 *
471 * Return :
472 * int
473 * return 1: if FRUID information is available
474 * return 0: if FRUID information is not present
475 *
476 */
477
478 /* ARGSUSED */
479 int
fru_is_data_available(picl_nodehdl_t fru)480 fru_is_data_available(picl_nodehdl_t fru)
481 {
482 return (0);
483 }
484