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 */