xref: /illumos-gate/usr/src/uts/common/io/vuid_store.c (revision 7c478bd9)
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 
42 static void vuid_destroy_seg();
43 static Vuid_seg * vuid_copy_seg();
44 static Vuid_seg * vuid_find_seg();
45 static Vuid_value * vuid_add_value();
46 static 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 
57 void
58 vuid_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 
137 int
138 vuid_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 
160 void
161 vuid_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 
174 static void
175 vuid_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 
188 Vuid_state
189 vuid_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 
212 static Vuid_seg *
213 vuid_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 
244 static Vuid_seg *
245 vuid_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 
258 static Vuid_value *
259 vuid_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 
272 static Vuid_value *
273 vuid_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