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