/* * 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_reg_vdev_received(struct scst_event_user *event_user) { struct scst_event_reg_vdev_payload *p = (struct scst_event_reg_vdev_payload *)event_user->out_event.payload; printf("Virtual device %s registration received.\n", p->device_name); return; } 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)); /* fall 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_REG_VIRT_DEV) { handle_reg_vdev_received(event_user); } 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; }