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