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 2008 Sun Microsystems, Inc.  All rights reserved.
23  * Use is subject to license terms.
24  */
25 
26 
27 /*
28  * rseq implementation
29  */
30 
31 #include <sys/usb/clients/usbser/usbser_rseq.h>
32 
33 #ifdef _KERNEL
34 #include <sys/debug.h>
35 #include <sys/ddi.h>
36 #include <sys/sunddi.h>
37 /*LINTED E_STATIC_UNUSED*/
38 static long rseq_random();
39 #define	random	rseq_random
40 #else
41 #include <assert.h>
42 #define	ASSERT	assert
43 #include <stdlib.h>
44 #endif
45 
46 
47 /*ARGSUSED*/
48 static int
49 rseq_do_common(rseq_t *rseq, int num, uintptr_t arg, int flags, int fail_err,
50 		uintptr_t fail_num)
51 {
52 	int		i;
53 	rseq_step_t	*s;
54 	int		rval = RSEQ_OK;
55 
56 	for (i = 0; i < num; i++) {
57 		s = &rseq[i].r_do;
58 
59 		if (s->s_func == NULL) {
60 			continue;
61 		}
62 		s->s_rval = (i != fail_num) ? s->s_func(arg) : fail_err;
63 		rval = (s->s_cb) ? (s->s_cb(rseq, i, arg)) : RSEQ_OK;
64 
65 		if (rval == RSEQ_UNDO) {
66 			(void) rseq_undo(rseq, i, arg, flags);
67 			break;
68 		} else if (rval == RSEQ_ABORT) {
69 			break;
70 		}
71 		ASSERT(rval == RSEQ_OK);
72 	}
73 	return (rval);
74 }
75 
76 
77 /*ARGSUSED*/
78 static int
79 rseq_undo_common(rseq_t *rseq, int num, uintptr_t arg, int flags, int fail_err,
80 		uintptr_t fail_num)
81 {
82 	int		i;
83 	rseq_step_t	*s;
84 	int		rval = RSEQ_OK;
85 
86 	for (i = num - 1; i >= 0; i--) {
87 		s = &rseq[i].r_undo;
88 
89 		if (s->s_func == NULL) {
90 			continue;
91 		}
92 		s->s_rval = (i != fail_num) ? s->s_func(arg) : fail_err;
93 		rval = (s->s_cb) ? (s->s_cb(rseq, i, arg)) : RSEQ_OK;
94 
95 		if (rval == RSEQ_ABORT) {
96 			break;
97 		}
98 		ASSERT(rval == RSEQ_OK);
99 	}
100 	return (rval);
101 }
102 
103 
104 int
105 rseq_do(rseq_t *rseq, int num, uintptr_t arg, int flags)
106 {
107 	return (rseq_do_common(rseq, num, arg, flags, 0, -1));
108 }
109 
110 
111 int
112 rseq_undo(rseq_t *rseq, int num, uintptr_t arg, int flags)
113 {
114 	return (rseq_undo_common(rseq, num, arg, flags, 0, -1));
115 }
116 
117 #ifdef DEBUG
118 
119 #ifndef __lock_lint
120 
121 static int
122 rseq_debug(rseq_t *rseq, int num, uintptr_t arg, int flags, int scenario,
123 		uintptr_t sarg1, uintptr_t sarg2,
124 		int (*func)(rseq_t *, int, uintptr_t, int, int, uintptr_t))
125 {
126 	int	rnd, rval = RSEQ_OK, i;
127 
128 	switch (scenario) {
129 	case RSEQ_DBG_FAIL_ONE:
130 		rval = func(rseq, num, arg, flags, sarg1, sarg2);
131 		break;
132 	case RSEQ_DBG_FAIL_ONE_RANDOM:
133 		rnd = random() % num;
134 		rval = func(rseq, num, arg, flags, sarg1, rnd);
135 		break;
136 	case RSEQ_DBG_FAIL_ONEBYONE:
137 		for (i = 0; i < num; i++) {
138 			rval = func(rseq, num, arg, flags, sarg1, i);
139 			/*
140 			 * when aborted, the undo path is not executed, so we
141 			 * can't continue without the risk of resource leakage.
142 			 */
143 			if (rval == RSEQ_ABORT) {
144 				break;
145 			}
146 		}
147 		break;
148 	default:
149 		ASSERT(!"rseq_debug: incorrect debug scenario");
150 		rval = RSEQ_ABORT;
151 	}
152 	return (rval);
153 }
154 
155 
156 int
157 rseq_do_debug(rseq_t *rseq, int num, uintptr_t arg, int flags, int scenario,
158 		uintptr_t sarg1, uintptr_t sarg2)
159 {
160 	return (rseq_debug(rseq, num, arg, flags, scenario, sarg1, sarg2,
161 	    rseq_do_common));
162 }
163 
164 
165 int
166 rseq_undo_debug(rseq_t *rseq, int num, uintptr_t arg, int flags, int scenario,
167 		uintptr_t sarg1, uintptr_t sarg2)
168 {
169 	return (rseq_debug(rseq, num, arg, flags, scenario, sarg1, sarg2,
170 	    rseq_undo_common));
171 }
172 
173 #ifdef _KERNEL
174 static long
175 rseq_random()
176 {
177 	return (ddi_get_lbolt());
178 }
179 #endif /* _KERNEL */
180 
181 #endif /* __lock_lint */
182 
183 #endif /* DEBUG */
184