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