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