From c619567bbaab6902934b7da77c4f33a299557d6e Mon Sep 17 00:00:00 2001 From: Vladislav Bolkhovitin Date: Fri, 6 Nov 2015 03:48:24 +0000 Subject: [PATCH] SCST events sample user space consumer Prepared with help from Prasidh Srikanth git-svn-id: http://svn.code.sf.net/p/scst/svn/trunk@6581 d57e44dd-8a1f-0410-8b47-8ef2f437770f --- usr/Makefile | 11 ++ usr/events/Makefile | 102 ++++++++++++++ usr/events/README | 2 + usr/events/debug.c | 1 + usr/events/events.c | 326 ++++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 442 insertions(+) create mode 100644 usr/events/Makefile create mode 100644 usr/events/README create mode 100644 usr/events/debug.c create mode 100644 usr/events/events.c diff --git a/usr/Makefile b/usr/Makefile index 77cb77135..85bed6073 100644 --- a/usr/Makefile +++ b/usr/Makefile @@ -23,46 +23,57 @@ SHELL=/bin/bash FILEIO_DIR=fileio STPGD_DIR=stpgd +EVENTS_DIR=events all: cd $(FILEIO_DIR) && $(MAKE) $@ cd $(STPGD_DIR) && $(MAKE) $@ +# cd $(EVENTS_DIR) && $(MAKE) $@ install: cd $(FILEIO_DIR) && $(MAKE) $@ cd $(STPGD_DIR) && $(MAKE) $@ +# cd $(EVENTS_DIR) && $(MAKE) $@ uninstall: cd $(FILEIO_DIR) && $(MAKE) $@ cd $(STPGD_DIR) && $(MAKE) $@ + cd $(EVENTS_DIR) && $(MAKE) $@ clean: cd $(FILEIO_DIR) && $(MAKE) $@ cd $(STPGD_DIR) && $(MAKE) $@ + cd $(EVENTS_DIR) && $(MAKE) $@ extraclean: cd $(FILEIO_DIR) && $(MAKE) $@ cd $(STPGD_DIR) && $(MAKE) $@ + cd $(EVENTS_DIR) && $(MAKE) $@ 2release: cd $(FILEIO_DIR) && $(MAKE) $@ cd $(STPGD_DIR) && $(MAKE) $@ + cd $(EVENTS_DIR) && $(MAKE) $@ 2debug: cd $(FILEIO_DIR) && $(MAKE) $@ cd $(STPGD_DIR) && $(MAKE) $@ + cd $(EVENTS_DIR) && $(MAKE) $@ 2perf: cd $(FILEIO_DIR) && $(MAKE) $@ cd $(STPGD_DIR) && $(MAKE) $@ + cd $(EVENTS_DIR) && $(MAKE) $@ disable_proc: cd $(FILEIO_DIR) && $(MAKE) $@ cd $(STPGD_DIR) && $(MAKE) $@ + cd $(EVENTS_DIR) && $(MAKE) $@ enable_proc: cd $(FILEIO_DIR) && $(MAKE) $@ cd $(STPGD_DIR) && $(MAKE) $@ + cd $(EVENTS_DIR) && $(MAKE) $@ help: @echo " all (the default) : make all" diff --git a/usr/events/Makefile b/usr/events/Makefile new file mode 100644 index 000000000..ffce7d2d7 --- /dev/null +++ b/usr/events/Makefile @@ -0,0 +1,102 @@ +ifndef PREFIX + PREFIX=/usr/local +endif + +SHELL=/bin/bash + +SRCS_F = events.c debug.c +OBJS_F = $(SRCS_F:.c=.o) + +#SRCS_C = +#OBJS_C = $(SRCS_C:.c=.o) + +SCST_INC_DIR := $(shell if [ -e "$$PWD/../../scst" ]; \ + then echo "$$PWD/../../scst/include"; \ + else echo "$(DESTDIR)$(PREFIX)/include/scst"; fi) +DEBUG_INC_DIR := ../include +INSTALL_DIR := $(DESTDIR)$(PREFIX)/bin/scst + +CFLAGS += -O2 -Wall -Wextra -Wno-unused-parameter -Wstrict-prototypes \ + -I$(SCST_INC_DIR) -I$(DEBUG_INC_DIR) -D_GNU_SOURCE -D__USE_FILE_OFFSET64 \ + -D__USE_LARGEFILE64 +PROGS = events +LIBS = -lpthread + +CFLAGS += -DEXTRACHECKS +#CFLAGS += -DTRACING +CFLAGS += -DDEBUG -g -fno-inline -fno-inline-functions +CFLAGS += -W -Wno-unused-parameter +CFLAGS += $(LOCAL_CFLAGS) + +#CFLAGS += -DDEBUG_NOMEM + +all: $(PROGS) + +events: .depend_f $(OBJS_F) + $(CC) $(OBJS_F) $(LIBS) $(LOCAL_LD_FLAGS) -o $@ + +#cdrom_tgt: .depend_c $(OBJS_C) +# $(CC) $(OBJS_C) $(LIBS) $(LOCAL_LD_FLAGS) -o $@ + +ifeq (.depend_f,$(wildcard .depend_f)) +-include .depend_f +endif + +#ifeq (.depend_c,$(wildcard .depend_c)) +#-include .depend_c +#endif + +%.o: %.c Makefile + $(CC) -c -o $(@) $(CFLAGS) $(<) + +.depend_f: + $(CC) -M $(CFLAGS) $(SRCS_F) >$(@) + +#.depend_c: +# $(CC) -M $(CFLAGS) $(SRCS_C) >$(@) + +install: all + install -d $(INSTALL_DIR) + install -m 755 $(PROGS) $(INSTALL_DIR) + +uninstall: + rm -f $(INSTALL_DIR)/$(PROGS) + rm -rf $(INSTALL_DIR) + +clean: + rm -f *.o $(PROGS) .depend* + +extraclean: clean + rm -f *.orig *.rej + +2release: + sed -i.aa s/"^C\?FLAGS += \-DEXTRACHECKS"/"#CFLAGS += \-DEXTRACHECKS"/ Makefile + grep "^#CFLAGS += \-DEXTRACHECKS" Makefile >/dev/null + sed -i.aa s/"^#\?CFLAGS += \-DTRACING"/"CFLAGS += \-DTRACING"/ Makefile + grep "^CFLAGS += \-DTRACING" Makefile >/dev/null + sed -i.aa s/"^C\?FLAGS += \-DDEBUG -g -fno-inline -fno-inline-functions"/"#CFLAGS += \-DDEBUG -g -fno-inline -fno-inline-functions"/ Makefile + grep "^#CFLAGS += \-DDEBUG -g -fno-inline -fno-inline-functions" Makefile >/dev/null + rm Makefile.aa + +2debug: + sed -i.aa s/"^#\?CFLAGS += \-DEXTRACHECKS"/"CFLAGS += \-DEXTRACHECKS"/ Makefile + grep "^CFLAGS += \-DEXTRACHECKS" Makefile >/dev/null + sed -i.aa s/"^C\?FLAGS += \-DTRACING"/"#CFLAGS += \-DTRACING"/ Makefile + grep "^#CFLAGS += \-DTRACING" Makefile >/dev/null + sed -i.aa s/"^#\?CFLAGS += \-DDEBUG -g -fno-inline -fno-inline-functions"/"CFLAGS += \-DDEBUG -g -fno-inline -fno-inline-functions"/ Makefile + grep "^CFLAGS += \-DDEBUG -g -fno-inline -fno-inline-functions" Makefile >/dev/null + rm Makefile.aa + +2perf: + sed -i.aa s/"^C\?FLAGS += \-DEXTRACHECKS"/"#CFLAGS += \-DEXTRACHECKS"/ Makefile + grep "^#CFLAGS += \-DEXTRACHECKS" Makefile >/dev/null + sed -i.aa s/"^C\?FLAGS += \-DTRACING"/"#CFLAGS += \-DTRACING"/ Makefile + grep "^#CFLAGS += \-DTRACING" Makefile >/dev/null + sed -i.aa s/"^C\?FLAGS += \-DDEBUG -g -fno-inline -fno-inline-functions"/"#CFLAGS += \-DDEBUG -g -fno-inline -fno-inline-functions"/ Makefile + grep "^#CFLAGS += \-DDEBUG -g -fno-inline -fno-inline-functions" Makefile >/dev/null + rm Makefile.aa + +release-archive: + ../../scripts/generate-release-archive events "$$(sed -n 's/^#define[[:blank:]]VERSION_STR[[:blank:]]*\"\([^\"]*\)\".*/\1/p' events.c)" + +.PHONY: all install uninstall clean extraclean 2release 2debug 2perf diff --git a/usr/events/README b/usr/events/README new file mode 100644 index 000000000..e354bb4dd --- /dev/null +++ b/usr/events/README @@ -0,0 +1,2 @@ +This is test/demo application for SCST events subsystem. For more +information about this subsystem, see scst_event.h file. diff --git a/usr/events/debug.c b/usr/events/debug.c new file mode 100644 index 000000000..03c08a556 --- /dev/null +++ b/usr/events/debug.c @@ -0,0 +1 @@ +#include "../include/debug.c" diff --git a/usr/events/events.c b/usr/events/events.c new file mode 100644 index 000000000..4cdf896e4 --- /dev/null +++ b/usr/events/events.c @@ -0,0 +1,326 @@ +/* + * events.c + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "version.h" +#include "debug.h" +#include "scst_event.h" + +char *app_name; + +#if defined(DEBUG) || defined(TRACING) + +#ifdef DEBUG +/*#define DEFAULT_LOG_FLAGS (TRACE_ALL & ~TRACE_MEMORY & ~TRACE_BUFF \ + & ~TRACE_FUNCTION) +#define DEFAULT_LOG_FLAGS (TRACE_ALL & ~TRACE_MEMORY & ~TRACE_BUFF & \ + ~TRACE_SCSI & ~TRACE_SCSI_SERIALIZING & ~TRACE_DEBUG) +*/ +#define DEFAULT_LOG_FLAGS (TRACE_OUT_OF_MEM | TRACE_MINOR | TRACE_PID | \ + TRACE_FUNCTION | TRACE_SPECIAL | TRACE_MGMT | TRACE_MGMT_DEBUG | \ + TRACE_TIME) + +#define TRACE_SN(args...) TRACE(TRACE_SCSI_SERIALIZING, args) + +#else /* DEBUG */ + +# ifdef TRACING +#define DEFAULT_LOG_FLAGS (TRACE_OUT_OF_MEM | TRACE_MGMT | \ + TRACE_TIME | TRACE_SPECIAL) +# else +#define DEFAULT_LOG_FLAGS 0 +# endif +#endif /* DEBUG */ + +bool log_daemon = false; /* needed for the tracing infrastructure */ +unsigned long trace_flag = DEFAULT_LOG_FLAGS; +#endif /* defined(DEBUG) || defined(TRACING) */ + +static struct option const long_options[] = { + {"allowed_event", required_argument, 0, 'e'}, + {"allowed_issuer", required_argument, 0, 'i'}, + {"non_blocking", no_argument, 0, 'n'}, +#if defined(DEBUG) || defined(TRACING) + {"debug", required_argument, 0, 'd'}, +#endif + {"version", no_argument, 0, 'v'}, + {"help", no_argument, 0, 'h'}, + {0, 0, 0, 0}, +}; + +#define MAX_ALLOWED_EVENTS 16 +static struct scst_event allowed_events[MAX_ALLOWED_EVENTS]; +static int allowed_events_num; +static int non_blocking; + +static void usage(void) +{ + printf("Usage: %s [OPTIONS]\n", app_name); + printf("\nSCST events testing program\n"); + printf(" -e, --allowed_event=code Allowed event code, 0 - any event\n"); + printf(" -i, --allowed_issuer=issuer Allowed issuer, * - any issuer\n"); + printf(" -n, --non_blocking Use non-blocking operations\n"); +#if defined(DEBUG) || defined(TRACING) + printf(" -d, --debug=level Debug tracing level\n"); +#endif +} + +static void handle_tm_received(struct scst_event_user *event_user) +{ + struct scst_event_tm_fn_received_payload *p = (struct scst_event_tm_fn_received_payload *)event_user->out_event.payload; + + printf("fn %d, device %s\n", p->fn, p->device_name); + + return; +} + +int main(int argc, char **argv) +{ + int res = 0, i; + int ch, longindex; + int event_fd; + uint8_t event_user_buf[10240]; + struct scst_event_user *event_user = (struct scst_event_user *)event_user_buf; + struct pollfd pl; + + setlinebuf(stdout); + + res = debug_init(); + if (res != 0) + goto out; + + app_name = argv[0]; + + while ((ch = getopt_long(argc, argv, "+e:i:d:nhv", + long_options, &longindex)) >= 0) { + switch (ch) { + case 'e': + if (allowed_events[allowed_events_num].event_code != 0) { + allowed_events_num++; + if (allowed_events_num >= MAX_ALLOWED_EVENTS) { + PRINT_ERROR("Too many allowed events %d", + allowed_events_num); + exit(1); + } + } + allowed_events[allowed_events_num].event_code = atoi(optarg); + break; + case 'i': + if (allowed_events[allowed_events_num].issuer_name[0] != '\0') { + allowed_events_num++; + if (allowed_events_num >= MAX_ALLOWED_EVENTS) { + PRINT_ERROR("Too many allowed events %d", + allowed_events_num); + exit(1); + } + } + strncpy(allowed_events[allowed_events_num].issuer_name, + optarg, sizeof(allowed_events[allowed_events_num].issuer_name)); + allowed_events[allowed_events_num].issuer_name[ + sizeof(allowed_events[allowed_events_num].issuer_name)-1] = '\0'; + break; + case 'n': + non_blocking = 1; + break; +#if defined(DEBUG) || defined(TRACING) + case 'd': + trace_flag = strtol(optarg, (char **)NULL, 0); + break; +#endif + case 'v': + printf("%s version %s\n", app_name, VERSION_STR); + goto out_done; + default: + goto out_usage; + } + } + + if (allowed_events_num == 0) { + if ((allowed_events[0].event_code == 0) && + (allowed_events[0].issuer_name[0] == '\0')) + allowed_events[0].issuer_name[0] = '*'; + } + + allowed_events_num++; + +#ifdef DEBUG + PRINT_INFO("trace_flag %lx", trace_flag); +#endif + + if (non_blocking) + PRINT_INFO("%s", "NON-BLOCKING"); + + event_fd = open(SCST_EVENT_DEV, O_RDWR | (non_blocking ? O_NONBLOCK : 0)); + if (event_fd < 0) { + res = -errno; + PRINT_ERROR("Unable to open SCST event device %s (%s)", + SCST_EVENT_DEV, strerror(-res)); + goto out_done; + } + + memset(&pl, 0, sizeof(pl)); + pl.fd = event_fd; + pl.events = POLLIN; + + for (i = 0; i < allowed_events_num; i++) { + struct scst_event e; + + PRINT_INFO("Setting allowed event code %d, issuer_name %s", + allowed_events[i].event_code, + allowed_events[i].issuer_name); + memset(&e, 0, sizeof(e)); + e.event_code = allowed_events[i].event_code; + strncpy(e.issuer_name, allowed_events[i].issuer_name, + sizeof(e.issuer_name)); + e.issuer_name[sizeof(e.issuer_name)-1] = '\0'; + + res = ioctl(event_fd, SCST_EVENT_ALLOW_EVENT, &e); + if (res != 0) { + PRINT_ERROR("SCST_EVENT_ALLOW_EVENT failed: %s (res %d)", + strerror(errno), res); + goto out_done; + } + } + + while (1) { + memset(event_user_buf, 0, sizeof(event_user_buf)); + event_user->max_event_size = sizeof(event_user_buf); + res = ioctl(event_fd, SCST_EVENT_GET_NEXT_EVENT, event_user); + if (res != 0) { + res = errno; + switch (res) { + case ESRCH: + case EBUSY: + TRACE_MGMT_DBG("SCST_EVENT_GET_NEXT_EVENT returned " + "%d (%s)", res, strerror(res)); + /* go through */ + case EINTR: + continue; + case EAGAIN: + TRACE_DBG("SCST_EVENT_GET_NEXT_EVENT, returned " + "EAGAIN (%d)", res); + if (non_blocking) + break; + else + continue; + default: + PRINT_ERROR("SCST_EVENT_GET_NEXT_EVENT failed: %s (res %d)", + strerror(errno), res); + goto out_done; + } +again_poll: + res = poll(&pl, 1, 2000); + if (res > 0) + continue; + else if (res == 0) + goto again_poll; + else { + res = errno; + switch (res) { + case ESRCH: + case EBUSY: + case EAGAIN: + TRACE_MGMT_DBG("poll() returned %d " + "(%s)", res, strerror(res)); + case EINTR: + goto again_poll; + default: + PRINT_ERROR("poll() failed: %s", strerror(res)); +#if 1 + goto again_poll; +#else + goto out_close; +#endif + } + } + + } + + PRINT_INFO("\nevent_code %d, issuer_name %s", + event_user->out_event.event_code, + event_user->out_event.issuer_name); + if (event_user->out_event.payload_len != 0) + PRINT_BUFFER("payoad", event_user->out_event.payload, + event_user->out_event.payload_len); + PRINT_INFO("%s", ""); + + if (event_user->out_event.event_code == 0x12345) { + struct scst_event_notify_done d; + + PRINT_INFO("%s", "Press any key to send reply to event " + "0x12345"); + getchar(); + + memset(&d, 0, sizeof(d)); + d.event_id = event_user->out_event.event_id; + d.status = -19; + res = ioctl(event_fd, SCST_EVENT_NOTIFY_DONE, &d); + if (res != 0) + PRINT_ERROR("SCST_EVENT_NOTIFY_DONE failed: %s " + "(res %d)", strerror(errno), res); + } else if (event_user->out_event.event_code == SCST_EVENT_TM_FN_RECEIVED) + handle_tm_received(event_user); + else if (event_user->out_event.event_code == SCST_EVENT_TM_FN_RECEIVED) { + struct scst_event_notify_done d; + + memset(&d, 0, sizeof(d)); + d.event_id = event_user->out_event.event_id; + d.status = -20; + res = ioctl(event_fd, SCST_EVENT_NOTIFY_DONE, &d); + if (res != 0) + PRINT_ERROR("SCST_EVENT_NOTIFY_DONE failed: %s " + "(res %d)", strerror(errno), res); + } + +#if 0 + { + struct scst_event e; + + PRINT_INFO("Deleting allowed event code %d, issuer_name %s", + allowed_events[0].event_code, + allowed_events[0].issuer_name); + memset(&e, 0, sizeof(e)); + e.event_code = allowed_events[0].event_code; + strncpy(e.issuer_name, allowed_events[0].issuer_name, + sizeof(e.issuer_name)); + e.issuer_name[sizeof(e.issuer_name)-1] = '\0'; + + res = ioctl(event_fd, SCST_EVENT_DISALLOW_EVENT, &e); + if (res != 0) { + PRINT_ERROR("SCST_EVENT_DISALLOW_EVENT failed: " + "%s (res %d)", strerror(errno), res); + } + } +#endif + } + +out_done: + debug_done(); + +out: + return res; + +out_usage: + usage(); + goto out_done; +}