#include <sys/usb/clients/usbser/usbser_rseq.h>
#ifdef _KERNEL
#include <sys/debug.h>
#include <sys/ddi.h>
#include <sys/sunddi.h>
static long rseq_random();
#define random rseq_random
#else
#include <assert.h>
#define ASSERT assert
#include <stdlib.h>
#endif
static int
rseq_do_common(rseq_t *rseq, int num, uintptr_t arg, int flags, int fail_err,
uintptr_t fail_num)
{
int i;
rseq_step_t *s;
int rval = RSEQ_OK;
for (i = 0; i < num; i++) {
s = &rseq[i].r_do;
if (s->s_func == NULL) {
continue;
}
s->s_rval = (i != fail_num) ? s->s_func(arg) : fail_err;
rval = (s->s_cb) ? (s->s_cb(rseq, i, arg)) : RSEQ_OK;
if (rval == RSEQ_UNDO) {
(void) rseq_undo(rseq, i, arg, flags);
break;
} else if (rval == RSEQ_ABORT) {
break;
}
ASSERT(rval == RSEQ_OK);
}
return (rval);
}
static int
rseq_undo_common(rseq_t *rseq, int num, uintptr_t arg, int flags, int fail_err,
uintptr_t fail_num)
{
int i;
rseq_step_t *s;
int rval = RSEQ_OK;
for (i = num - 1; i >= 0; i--) {
s = &rseq[i].r_undo;
if (s->s_func == NULL) {
continue;
}
s->s_rval = (i != fail_num) ? s->s_func(arg) : fail_err;
rval = (s->s_cb) ? (s->s_cb(rseq, i, arg)) : RSEQ_OK;
if (rval == RSEQ_ABORT) {
break;
}
ASSERT(rval == RSEQ_OK);
}
return (rval);
}
int
rseq_do(rseq_t *rseq, int num, uintptr_t arg, int flags)
{
return (rseq_do_common(rseq, num, arg, flags, 0, -1));
}
int
rseq_undo(rseq_t *rseq, int num, uintptr_t arg, int flags)
{
return (rseq_undo_common(rseq, num, arg, flags, 0, -1));
}
#ifdef DEBUG
#ifndef __lock_lint
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))
{
int rnd, rval = RSEQ_OK, i;
switch (scenario) {
case RSEQ_DBG_FAIL_ONE:
rval = func(rseq, num, arg, flags, sarg1, sarg2);
break;
case RSEQ_DBG_FAIL_ONE_RANDOM:
rnd = random() % num;
rval = func(rseq, num, arg, flags, sarg1, rnd);
break;
case RSEQ_DBG_FAIL_ONEBYONE:
for (i = 0; i < num; i++) {
rval = func(rseq, num, arg, flags, sarg1, i);
if (rval == RSEQ_ABORT) {
break;
}
}
break;
default:
ASSERT(!"rseq_debug: incorrect debug scenario");
rval = RSEQ_ABORT;
}
return (rval);
}
int
rseq_do_debug(rseq_t *rseq, int num, uintptr_t arg, int flags, int scenario,
uintptr_t sarg1, uintptr_t sarg2)
{
return (rseq_debug(rseq, num, arg, flags, scenario, sarg1, sarg2,
rseq_do_common));
}
int
rseq_undo_debug(rseq_t *rseq, int num, uintptr_t arg, int flags, int scenario,
uintptr_t sarg1, uintptr_t sarg2)
{
return (rseq_debug(rseq, num, arg, flags, scenario, sarg1, sarg2,
rseq_undo_common));
}
#ifdef _KERNEL
static long
rseq_random()
{
return (ddi_get_lbolt());
}
#endif
#endif
#endif