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