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 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 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 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 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 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 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 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 174 rseq_random() 175 { 176 return (ddi_get_lbolt()); 177 } 178 #endif /* _KERNEL */ 179 180 #endif /* __lock_lint */ 181 182 #endif /* DEBUG */