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