xref: /illumos-gate/usr/src/uts/sun4u/ngdr/io/dr_util.c (revision 2b24ab6b3865caeede9eeb9db6b83e1d89dcd1ea)
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  * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
23  * Use is subject to license terms.
24  */
25 
26 #pragma ident	"%Z%%M%	%I%	%E% SMI"
27 
28 #include <sys/types.h>
29 #include <sys/cmn_err.h>
30 #include <sys/param.h>		/* for NULL */
31 #include <sys/sbd_ioctl.h>
32 #include <sys/dr_util.h>
33 #include <sys/varargs.h>
34 #include <sys/sysmacros.h>
35 #include <sys/systm.h>
36 
37 /* sbd_etab[] and sbd_etab_len provided by sbdgenerr.pl */
38 extern sbd_etab_t sbd_etab[];
39 extern int sbd_etab_len;
40 
41 sbd_error_t *
42 sbd_err_new(int e_code, char *fmt, va_list args)
43 {
44 	sbd_error_t	*new;
45 
46 	new = GETSTRUCT(sbd_error_t, 1);
47 	new->e_code = e_code;
48 
49 	if (fmt)
50 		(void) vsnprintf(new->e_rsc, sizeof (new->e_rsc), fmt, args);
51 
52 	return (new);
53 }
54 
55 void
56 sbd_err_log(sbd_error_t *ep, int ce)
57 {
58 	char		 buf[32];
59 	char		*fmt;
60 	char		*txt;
61 	int		 i;
62 	sbd_etab_t	*tp;
63 
64 	if (!ep)
65 		return;
66 
67 	if (ep->e_rsc[0] == '\0')
68 		fmt = "%s";
69 	else
70 		fmt = "%s: %s";
71 
72 	for (tp = sbd_etab, i = 0; i < sbd_etab_len; i++, tp++)
73 		if (ep->e_code >= tp->t_base && ep->e_code <= tp->t_bnd)
74 			break;
75 
76 	if (i < sbd_etab_len)
77 		txt = tp->t_text[ep->e_code - tp->t_base];
78 	else {
79 		snprintf(buf, sizeof (buf), "error %d", ep->e_code);
80 		txt = buf;
81 	}
82 
83 	cmn_err(ce, fmt, txt, ep->e_rsc);
84 }
85 
86 void
87 sbd_err_clear(sbd_error_t **ep)
88 {
89 	FREESTRUCT(*ep, sbd_error_t, 1);
90 	*ep = NULL;
91 }
92 
93 void
94 sbd_err_set_c(sbd_error_t **ep, int ce, int e_code, char *fmt, ...)
95 {
96 	sbd_error_t	*tmp;
97 	va_list		args;
98 
99 	va_start(args, fmt);
100 
101 	tmp = sbd_err_new(e_code, fmt, args);
102 
103 	sbd_err_log(tmp, ce);
104 
105 	if (*ep == NULL)
106 		*ep = tmp;
107 	else
108 		sbd_err_clear(&tmp);
109 
110 	va_end(args);
111 }
112 
113 void
114 sbd_err_set(sbd_error_t **ep, int ce, int e_code, char *fmt, ...)
115 {
116 	sbd_error_t	*tmp;
117 	va_list		args;
118 
119 	va_start(args, fmt);
120 
121 	tmp = sbd_err_new(e_code, fmt, args);
122 
123 	sbd_err_log(tmp, ce);
124 
125 	*ep = tmp;
126 
127 	va_end(args);
128 }
129 
130 sbd_error_t *
131 drerr_new_v(int e_code, char *fmt, va_list args)
132 {
133 	return (sbd_err_new(e_code, fmt, args));
134 }
135 
136 sbd_error_t *
137 drerr_new(int log, int e_code, char *fmt, ...)
138 {
139 	sbd_error_t	*ep;
140 	va_list		 args;
141 
142 	va_start(args, fmt);
143 	ep = sbd_err_new(e_code, fmt, args);
144 	va_end(args);
145 
146 	if (log)
147 		sbd_err_log(ep, CE_WARN);
148 
149 	return (ep);
150 }
151 
152 void
153 drerr_set_c(int log, sbd_error_t **ep, int e_code, char *fmt, ...)
154 {
155 	sbd_error_t	*err;
156 	va_list		 args;
157 
158 	va_start(args, fmt);
159 	err = sbd_err_new(e_code, fmt, args);
160 	va_end(args);
161 
162 	if (log)
163 		sbd_err_log(err, CE_WARN);
164 
165 	if (*ep == NULL)
166 		*ep = err;
167 	else
168 		sbd_err_clear(&err);
169 }
170 
171 
172 /*
173  * Memlist support.
174  */
175 void
176 dr_memlist_delete(struct memlist *mlist)
177 {
178 	register struct memlist	*ml;
179 
180 	for (ml = mlist; ml; ml = mlist) {
181 		mlist = ml->next;
182 		FREESTRUCT(ml, struct memlist, 1);
183 	}
184 }
185 
186 int
187 dr_memlist_intersect(struct memlist *al, struct memlist *bl)
188 {
189 	uint64_t	astart, aend, bstart, bend;
190 
191 	if ((al == NULL) || (bl == NULL))
192 		return (0);
193 
194 	aend = al->address + al->size;
195 	bstart = bl->address;
196 	bend = bl->address + bl->size;
197 
198 	while (al && bl) {
199 		while (al && (aend <= bstart))
200 			if ((al = al->next) != NULL)
201 				aend = al->address + al->size;
202 		if (al == NULL)
203 			return (0);
204 
205 		if ((astart = al->address) <= bstart)
206 			return (1);
207 
208 		while (bl && (bend <= astart))
209 			if ((bl = bl->next) != NULL)
210 				bend = bl->address + bl->size;
211 		if (bl == NULL)
212 			return (0);
213 
214 		if ((bstart = bl->address) <= astart)
215 			return (1);
216 	}
217 
218 	return (0);
219 }
220 
221 void
222 dr_memlist_coalesce(struct memlist *mlist)
223 {
224 	uint64_t	end, nend;
225 
226 	if ((mlist == NULL) || (mlist->next == NULL))
227 		return;
228 
229 	while (mlist->next) {
230 		end = mlist->address + mlist->size;
231 		if (mlist->next->address <= end) {
232 			struct memlist 	*nl;
233 
234 			nend = mlist->next->address + mlist->next->size;
235 			if (nend > end)
236 				mlist->size += (nend - end);
237 			nl = mlist->next;
238 			mlist->next = mlist->next->next;
239 			if (nl) {
240 				FREESTRUCT(nl, struct memlist, 1);
241 			}
242 			if (mlist->next)
243 				mlist->next->prev = mlist;
244 		} else {
245 			mlist = mlist->next;
246 		}
247 	}
248 }
249 
250 #ifdef DEBUG
251 void
252 memlist_dump(struct memlist *mlist)
253 {
254 	register struct memlist *ml;
255 
256 	if (mlist == NULL)
257 		printf("memlist> EMPTY\n");
258 	else for (ml = mlist; ml; ml = ml->next)
259 		printf("memlist> 0x%lx, 0x%lx\n", ml->address, ml->size);
260 }
261 #endif
262 
263 struct memlist *
264 dr_memlist_dup(struct memlist *mlist)
265 {
266 	struct memlist *hl = NULL, *tl, **mlp;
267 
268 	if (mlist == NULL)
269 		return (NULL);
270 
271 	mlp = &hl;
272 	tl = *mlp;
273 	for (; mlist; mlist = mlist->next) {
274 		*mlp = GETSTRUCT(struct memlist, 1);
275 		(*mlp)->address = mlist->address;
276 		(*mlp)->size = mlist->size;
277 		(*mlp)->prev = tl;
278 		tl = *mlp;
279 		mlp = &((*mlp)->next);
280 	}
281 	*mlp = NULL;
282 
283 	return (hl);
284 }
285 
286 struct memlist *
287 dr_memlist_add_span(struct memlist *mlist, uint64_t base, uint64_t len)
288 {
289 	struct memlist	*ml, *tl, *nl;
290 
291 	if (len == 0ull)
292 		return (NULL);
293 
294 	if (mlist == NULL) {
295 		mlist = GETSTRUCT(struct memlist, 1);
296 		mlist->address = base;
297 		mlist->size = len;
298 		mlist->next = mlist->prev = NULL;
299 
300 		return (mlist);
301 	}
302 
303 	for (tl = ml = mlist; ml; tl = ml, ml = ml->next) {
304 		if (base < ml->address) {
305 			if ((base + len) < ml->address) {
306 				nl = GETSTRUCT(struct memlist, 1);
307 				nl->address = base;
308 				nl->size = len;
309 				nl->next = ml;
310 				if ((nl->prev = ml->prev) != NULL)
311 					nl->prev->next = nl;
312 				ml->prev = nl;
313 				if (mlist == ml)
314 					mlist = nl;
315 			} else {
316 				ml->size = MAX((base + len),
317 					(ml->address + ml->size)) -
318 					base;
319 				ml->address = base;
320 			}
321 			break;
322 
323 		} else if (base <= (ml->address + ml->size)) {
324 			ml->size = MAX((base + len),
325 				(ml->address + ml->size)) -
326 				MIN(ml->address, base);
327 			ml->address = MIN(ml->address, base);
328 			break;
329 		}
330 	}
331 	if (ml == NULL) {
332 		nl = GETSTRUCT(struct memlist, 1);
333 		nl->address = base;
334 		nl->size = len;
335 		nl->next = NULL;
336 		nl->prev = tl;
337 		tl->next = nl;
338 	}
339 
340 	dr_memlist_coalesce(mlist);
341 
342 	return (mlist);
343 }
344 
345 struct memlist *
346 dr_memlist_del_span(struct memlist *mlist, uint64_t base, uint64_t len)
347 {
348 	uint64_t	end;
349 	struct memlist	*ml, *tl, *nlp;
350 
351 	if (mlist == NULL)
352 		return (NULL);
353 
354 	end = base + len;
355 	if ((end <= mlist->address) || (base == end))
356 		return (mlist);
357 
358 	for (tl = ml = mlist; ml; tl = ml, ml = nlp) {
359 		uint64_t	mend;
360 
361 		nlp = ml->next;
362 
363 		if (end <= ml->address)
364 			break;
365 
366 		mend = ml->address + ml->size;
367 		if (base < mend) {
368 			if (base <= ml->address) {
369 				ml->address = end;
370 				if (end >= mend)
371 					ml->size = 0ull;
372 				else
373 					ml->size = mend - ml->address;
374 			} else {
375 				ml->size = base - ml->address;
376 				if (end < mend) {
377 					struct memlist	*nl;
378 					/*
379 					 * splitting an memlist entry.
380 					 */
381 					nl = GETSTRUCT(struct memlist, 1);
382 					nl->address = end;
383 					nl->size = mend - nl->address;
384 					if ((nl->next = nlp) != NULL)
385 						nlp->prev = nl;
386 					nl->prev = ml;
387 					ml->next = nl;
388 					nlp = nl;
389 				}
390 			}
391 			if (ml->size == 0ull) {
392 				if (ml == mlist) {
393 					if ((mlist = nlp) != NULL)
394 						nlp->prev = NULL;
395 					FREESTRUCT(ml, struct memlist, 1);
396 					if (mlist == NULL)
397 						break;
398 					ml = nlp;
399 				} else {
400 					if ((tl->next = nlp) != NULL)
401 						nlp->prev = tl;
402 					FREESTRUCT(ml, struct memlist, 1);
403 					ml = tl;
404 				}
405 			}
406 		}
407 	}
408 
409 	return (mlist);
410 }
411 
412 /*
413  * add span without merging
414  */
415 struct memlist *
416 dr_memlist_cat_span(struct memlist *mlist, uint64_t base, uint64_t len)
417 {
418 	struct memlist	*ml, *tl, *nl;
419 
420 	if (len == 0ull)
421 		return (NULL);
422 
423 	if (mlist == NULL) {
424 		mlist = GETSTRUCT(struct memlist, 1);
425 		mlist->address = base;
426 		mlist->size = len;
427 		mlist->next = mlist->prev = NULL;
428 
429 		return (mlist);
430 	}
431 
432 	for (tl = ml = mlist; ml; tl = ml, ml = ml->next) {
433 		if (base < ml->address) {
434 			nl = GETSTRUCT(struct memlist, 1);
435 			nl->address = base;
436 			nl->size = len;
437 			nl->next = ml;
438 			if ((nl->prev = ml->prev) != NULL)
439 				nl->prev->next = nl;
440 			ml->prev = nl;
441 			if (mlist == ml)
442 				mlist = nl;
443 			break;
444 		}
445 	}
446 
447 	if (ml == NULL) {
448 		nl = GETSTRUCT(struct memlist, 1);
449 		nl->address = base;
450 		nl->size = len;
451 		nl->next = NULL;
452 		nl->prev = tl;
453 		tl->next = nl;
454 	}
455 
456 	return (mlist);
457 }
458