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