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
rseq_do_common(rseq_t * rseq,int num,uintptr_t arg,int flags,int fail_err,uintptr_t fail_num)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
rseq_undo_common(rseq_t * rseq,int num,uintptr_t arg,int flags,int fail_err,uintptr_t fail_num)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
rseq_do(rseq_t * rseq,int num,uintptr_t arg,int flags)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
rseq_undo(rseq_t * rseq,int num,uintptr_t arg,int flags)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
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))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
rseq_do_debug(rseq_t * rseq,int num,uintptr_t arg,int flags,int scenario,uintptr_t sarg1,uintptr_t sarg2)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
rseq_undo_debug(rseq_t * rseq,int num,uintptr_t arg,int flags,int scenario,uintptr_t sarg1,uintptr_t sarg2)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
rseq_random()175 rseq_random()
176 {
177 return (ddi_get_lbolt());
178 }
179 #endif /* _KERNEL */
180
181 #endif /* __lock_lint */
182
183 #endif /* DEBUG */
184