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 */
53container_hdl_t	fru_open_container(picl_nodehdl_t fru);
54int		fru_close_container(container_hdl_t fru);
55int		fru_get_num_sections(container_hdl_t container,
56		    door_cred_t *cred);
57int		fru_get_sections(container_hdl_t container, section_t *section,
58		    int max_sections, door_cred_t *cred);
59int		fru_get_num_segments(section_hdl_t section, door_cred_t *cred);
60int		fru_get_segments(section_hdl_t section, segment_t *segment,
61		    int max_segments, door_cred_t *cred);
62int		fru_add_segment(section_hdl_t section, segment_t *segment,
63		    section_hdl_t *newsection, door_cred_t *cred);
64int		fru_delete_segment(segment_hdl_t segment,
65		    section_hdl_t *newsection, door_cred_t *cred);
66ssize_t		fru_read_segment(segment_hdl_t segment, void *buffer,
67		    size_t nbytes, door_cred_t *cred);
68ssize_t		fru_write_segment(segment_hdl_t segment, const void *data,
69		    size_t nbytes, segment_hdl_t *newsegment,
70		    door_cred_t *cred);
71int		fru_get_num_packets(segment_hdl_t segment, door_cred_t *cred);
72int		fru_get_packets(segment_hdl_t segment, packet_t *packet,
73		    int max_packets, door_cred_t *cred);
74int		fru_update_payload(packet_hdl_t packet, const void *data,
75		    size_t nbytes, packet_hdl_t *newpacket, door_cred_t *cred);
76int		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);
79int		fru_delete_packet(packet_hdl_t packet,
80		    segment_hdl_t *newsegment, door_cred_t *cred);
81int 		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
90static int
91fru_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 */
110container_hdl_t
111fru_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*/
140int
141fru_close_container(container_hdl_t fru)
142{
143	if (fru_open_dev() == -1) {
144		return (-1);
145	}
146	return (0);
147}
148
149/*ARGSUSED*/
150int
151fru_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*/
168int
169fru_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, &sections) != 0) {
182		return (-1);
183	}
184	return (sections.fru_cnt);
185}
186
187/*ARGSUSED*/
188int
189fru_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*/
206int
207fru_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*/
226int
227fru_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
256int
257fru_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*/
282ssize_t
283fru_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*/
302ssize_t
303fru_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*/
324int
325fru_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*/
342int
343fru_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*/
362ssize_t
363fru_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
381int
382fru_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
408int
409fru_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
440int
441fru_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 */
481int
482fru_is_data_available(picl_nodehdl_t fru)
483{
484	return (0);
485}
486