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 (c) 1985-2001 by Sun Microsystems, Inc.
24 * All rights reserved.
25 */
26
27#pragma ident	"%Z%%M%	%I%	%E% SMI"
28
29/*
30 * Vuid_store.c - Implement the vuid_store.h event storage interface.
31 */
32
33#include <sys/types.h>
34#include <sys/time.h>
35#include <sys/kmem.h>
36#include <sys/systm.h>
37#include <sys/disp.h>
38#include <sys/vuid_event.h>
39#include <sys/vuid_state.h>
40#include <sys/vuid_store.h>
41
42static void vuid_destroy_seg();
43static Vuid_seg * vuid_copy_seg();
44static Vuid_seg * vuid_find_seg();
45static Vuid_value * vuid_add_value();
46static Vuid_value * vuid_find_value();
47
48#ifdef	_KERNEL
49#define	vuid_alloc(bytes) \
50	kmem_alloc((bytes), servicing_interrupt())
51#define	vuid_free(ptr, bytes)	kmem_free((ptr), (bytes))
52#else
53#define	vuid_alloc(bytes)	malloc((bytes))
54#define	vuid_free(ptr, bytes)	free((ptr))
55#endif	/* _KERNEL */
56
57void
58vuid_set_value(client_state_ptr, event)
59	Vuid_state *client_state_ptr;
60	register Firm_event *event;
61{
62	Vuid_seg **state_ptr = (Vuid_seg **)client_state_ptr;
63	Vuid_seg *state = *state_ptr;
64	register Vuid_seg *seg;
65	register Vuid_value *val_node;
66	register Vuid_value *pair_val_node;
67	register ushort_t offset = vuid_id_offset(event->id);
68	register ushort_t pair = event->pair;
69	int	int_bit, val_original;
70
71	/* Get (search for) seg from state assoicated with event */
72	if ((seg = vuid_find_seg(state, vuid_id_addr(event->id))) ==
73	    VUID_SEG_NULL) {
74		/* Allocate and initialize new seg for event */
75		seg = (Vuid_seg *) vuid_alloc(sizeof (*seg));
76		bzero((caddr_t)seg, sizeof (*seg));
77		seg->addr = vuid_id_addr(event->id);
78		/* Add the seg to state */
79		*state_ptr = seg;
80		seg->next = state;
81	}
82	int_bit = vuid_get_int_bit(seg, offset);
83	/* See if no value node and event value is not boolean */
84	if ((!int_bit) && vuid_int_value(event->value)) {
85		(void) vuid_add_value(seg, offset);
86		int_bit = 1;
87	}
88	/* If boolean event then set boolean bit */
89	if (!int_bit) {
90		if (event->value)
91			vuid_set_boolean_bit(seg, offset);
92		else
93			vuid_clear_boolean_bit(seg, offset);
94	} else {
95		/* Get (search for) value node (should be there) */
96		val_node = vuid_find_value(seg, offset);
97		val_original = val_node->value;
98		val_node->value = event->value;
99		switch (event->pair_type) {
100
101		case FE_PAIR_DELTA:
102			/* See if value node for pair */
103			if (!vuid_get_int_bit(seg, pair))
104				(void) vuid_add_value(seg, pair);
105			/* Get (search for) value node (should be there) */
106			pair_val_node = vuid_find_value(seg, pair);
107			/* Set pair value to difference */
108			pair_val_node->value = event->value - val_original;
109			break;
110
111		case FE_PAIR_ABSOLUTE:
112			/* See if value node for pair */
113			if (!vuid_get_int_bit(seg, pair))
114				(void) vuid_add_value(seg, pair);
115			/* Get (search for) value node (should be there) */
116			pair_val_node = vuid_find_value(seg, pair);
117			/* Add event value to pair value */
118			pair_val_node->value += event->value;
119			break;
120
121		default:
122			{}
123		}
124	}
125	/* Recursively call vuid_set_value if there is an associated pair */
126	if (event->pair_type == FE_PAIR_SET) {
127		Firm_event pair_event;
128
129		pair_event = *event;
130		pair_event.id = vuid_id_addr(event->id) | pair;
131		pair_event.pair_type = FE_PAIR_NONE;
132		pair_event.pair = 0;
133		vuid_set_value(client_state_ptr, &pair_event);
134	}
135}
136
137int
138vuid_get_value(client_state, id)
139	Vuid_state client_state;
140	ushort_t id;
141{
142	Vuid_seg *state = vuid_cstate_to_state(client_state);
143	register Vuid_seg *seg;
144	Vuid_value *val_node;
145	register ushort_t offset = vuid_id_offset(id);
146
147	/* Get (search for) seg from state assoicated with id */
148	if ((seg = vuid_find_seg(state, vuid_id_addr(id))) == VUID_SEG_NULL)
149		return (0);
150	/* If boolean event (i.e., no ints bit on) then return boolean value */
151	if (!vuid_get_int_bit(seg, offset))
152		return (vuid_get_boolean_bit(seg, offset) != 0);
153	else {
154		/* Get (search for) value node and return value */
155		val_node = vuid_find_value(seg, offset);
156		return (val_node->value);
157	}
158}
159
160void
161vuid_destroy_state(client_state)
162	Vuid_state client_state;
163{
164	Vuid_seg *state = vuid_cstate_to_state(client_state);
165	register Vuid_seg *seg;
166	Vuid_seg *seg_next;
167
168	for (seg = state; seg; seg = seg_next) {
169		seg_next = seg->next;
170		vuid_destroy_seg(seg);
171	}
172}
173
174static void
175vuid_destroy_seg(seg)
176	Vuid_seg *seg;
177{
178	register Vuid_value *val_node;
179	Vuid_value *val_node_next;
180
181	for (val_node = seg->list; val_node; val_node = val_node_next) {
182		val_node_next = val_node->next;
183		vuid_free((caddr_t)val_node, sizeof (Vuid_value));
184	}
185	vuid_free((caddr_t)seg, sizeof (Vuid_seg));
186}
187
188Vuid_state
189vuid_copy_state(client_state)
190	Vuid_state client_state;
191{
192	Vuid_seg *state = vuid_cstate_to_state(client_state);
193	register Vuid_seg *seg;
194	Vuid_seg *new_first_seg = VUID_SEG_NULL;
195	register Vuid_seg *new_previous_seg = VUID_SEG_NULL;
196	register Vuid_seg *new_seg;
197
198	for (seg = state; seg; seg = seg->next) {
199		new_seg = vuid_copy_seg(seg);
200		/* Remember first seg as state */
201		if (new_first_seg == VUID_SEG_NULL)
202			new_first_seg = new_seg;
203		/* Link segs together */
204		if (new_previous_seg != VUID_SEG_NULL)
205			new_previous_seg->next = new_seg;
206		/* Remember seg for linking later */
207		new_previous_seg = new_seg;
208	}
209	return ((Vuid_state) new_first_seg);
210}
211
212static Vuid_seg *
213vuid_copy_seg(seg)
214	Vuid_seg *seg;
215{
216	register Vuid_value *val_node;
217	Vuid_seg *new_seg;
218	register Vuid_value *new_previous_val = VUID_VALUE_NULL;
219	register Vuid_value *new_val;
220
221	/* Allocate and initialize new seg for event */
222	new_seg = (Vuid_seg *) vuid_alloc(sizeof (*seg));
223	*new_seg = *seg;
224	/* Terminate new pointer with null */
225	new_seg->next = VUID_SEG_NULL;
226	new_seg->list = VUID_VALUE_NULL;
227	/* Copy list elements */
228	for (val_node = seg->list; val_node; val_node = val_node->next) {
229		new_val = (Vuid_value *) vuid_alloc(sizeof (*new_val));
230		*new_val = *val_node;
231		new_val->next = VUID_VALUE_NULL;
232		/* Remember first value as head of list */
233		if (new_seg->list == VUID_VALUE_NULL)
234			new_seg->list = new_val;
235		/* Link vals together */
236		if (new_previous_val != VUID_VALUE_NULL)
237			new_previous_val->next = new_val;
238		/* Remember val for linking later */
239		new_previous_val = new_val;
240	}
241	return (new_seg);
242}
243
244static Vuid_seg *
245vuid_find_seg(state, addr)
246	Vuid_seg *state;
247	ushort_t addr;
248{
249	register Vuid_seg *seg;
250
251	for (seg = state; seg; seg = seg->next) {
252		if (seg->addr == addr)
253			return (seg);
254	}
255	return (VUID_SEG_NULL);
256}
257
258static Vuid_value *
259vuid_find_value(seg, offset)
260	Vuid_seg *seg;
261	ushort_t offset;
262{
263	register Vuid_value *val_node;
264
265	for (val_node = seg->list; val_node; val_node = val_node->next) {
266		if (vuid_id_offset(val_node->offset) == offset)
267			return (val_node);
268	}
269	return (VUID_VALUE_NULL);
270}
271
272static Vuid_value *
273vuid_add_value(seg, offset)
274	Vuid_seg *seg;
275	ushort_t offset;
276{
277	Vuid_value *list_tmp;
278	Vuid_value *val_node;
279
280	/* Allocate and initialize new value node for event */
281	val_node = (Vuid_value *) vuid_alloc(sizeof (*val_node));
282	bzero((caddr_t)val_node, sizeof (*val_node));
283	val_node->offset = offset;
284	/* Add the value node to list */
285	list_tmp = seg->list;
286	seg->list = val_node;
287	val_node->next = list_tmp;
288	vuid_set_int_bit(seg, offset);
289	/* Clear boolean bit for event */
290	vuid_clear_boolean_bit(seg, offset);
291	return (val_node);
292}
293