Codebase list tcmu / HEAD tcmu-synthesizer.c
HEAD

Tree @HEAD (Download .tar.gz)

tcmu-synthesizer.c @HEAD

4f7a835
33419b7
4f7a835
33419b7
 
 
 
4f7a835
 
 
 
 
 
 
 
 
 
 
 
 
 
 
81e22a1
7ac6c42
a2eb27b
 
 
4f7a835
 
 
 
 
 
 
b77784f
4f7a835
 
 
 
81e22a1
4f7a835
 
 
b77784f
4f7a835
 
b77784f
4f7a835
 
 
 
 
b77784f
4f7a835
706d671
4f7a835
 
 
b77784f
4f7a835
 
 
b77784f
4f7a835
 
 
 
 
0e78c0d
4f7a835
 
 
 
 
0e78c0d
4f7a835
 
81e22a1
706d671
4f7a835
 
 
 
 
 
 
 
 
 
 
81e22a1
4f7a835
 
a2eb27b
4f7a835
 
 
b77784f
4f7a835
 
 
 
 
 
 
 
 
 
 
a2eb27b
 
 
4f7a835
 
 
 
 
 
 
a2eb27b
 
4f7a835
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
81e22a1
4f7a835
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
81e22a1
4f7a835
 
8eb6e0c
4f7a835
 
 
 
 
 
 
 
a2eb27b
5846587
 
 
 
34e9adc
4f7a835
34e9adc
5846587
4f7a835
 
5846587
4f7a835
 
 
 
 
 
 
5846587
4f7a835
 
/*
 * Copyright (c) 2016 Red Hat, Inc.
 *
 * This file is licensed to you under your choice of the GNU Lesser
 * General Public License, version 2.1 or any later version (LGPLv2.1 or
 * later), or the Apache License 2.0.
 */

#define _GNU_SOURCE
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <sys/types.h>
#include <assert.h>
#include <glib.h>
#include <gio/gio.h>
#include <getopt.h>
#include <scsi/scsi.h>
#include "scsi_defs.h"

#include "libtcmu.h"
#include "version.h"
#include "libtcmu_config.h"
#include "libtcmu_log.h"
#include "scsi.h"

#define LOG_DIR "/var/log"

typedef struct {
	GIOChannel *gio;
	int watcher_id;
} syn_dev_t;

static int syn_handle_cmd(struct tcmu_device *dev, uint8_t *cdb,
			  struct iovec *iovec, size_t iov_cnt)
{
	uint8_t cmd;

	cmd = cdb[0];
	tcmu_dbg("syn handle cmd %d\n", cmd);

	switch (cmd) {
	case INQUIRY:
		return tcmu_emulate_inquiry(dev, NULL, cdb, iovec, iov_cnt);
		break;
	case TEST_UNIT_READY:
		return tcmu_emulate_test_unit_ready(cdb, iovec, iov_cnt);
	case SERVICE_ACTION_IN_16:
		if (cdb[1] == READ_CAPACITY_16)
			return tcmu_emulate_read_capacity_16(1 << 20,
							     512,
							     cdb, iovec,
							     iov_cnt);
		else
			return TCMU_STS_NOT_HANDLED;
		break;
	case MODE_SENSE:
	case MODE_SENSE_10:
		return tcmu_emulate_mode_sense(dev, cdb, iovec, iov_cnt);
		break;
	case MODE_SELECT:
	case MODE_SELECT_10:
		return tcmu_emulate_mode_select(dev, cdb, iovec, iov_cnt);
		break;
	case READ_6:
	case READ_10:
	case READ_12:
	case READ_16:
		return TCMU_STS_OK;

	case WRITE_6:
	case WRITE_10:
	case WRITE_12:
	case WRITE_16:
		return TCMU_STS_OK;

	default:
		tcmu_dbg("unknown command %x\n", cdb[0]);
		return TCMU_STS_NOT_HANDLED;
	}
}

static gboolean syn_dev_callback(GIOChannel *source,
				 GIOCondition condition,
				 gpointer data)
{
	int ret;
	struct tcmu_device *dev = data;
	struct tcmulib_cmd *cmd;

	tcmu_dbg("dev fd cb\n");
	tcmulib_processing_start(dev);

	while ((cmd = tcmulib_get_next_command(dev, 0)) != NULL) {
		ret = syn_handle_cmd(dev,
				     cmd->cdb,
				     cmd->iovec,
				     cmd->iov_cnt);
		tcmulib_command_complete(dev, cmd, ret);
	}

	tcmulib_processing_complete(dev);
	return TRUE;
}

static int syn_added(struct tcmu_device *dev)
{
	syn_dev_t *s = g_new0(syn_dev_t, 1);

	tcmu_dbg("added %s\n", tcmu_dev_get_cfgstring(dev));
	tcmu_dev_set_private(dev, s);
	s->gio = g_io_channel_unix_new(tcmu_dev_get_fd(dev));
	s->watcher_id = g_io_add_watch(s->gio, G_IO_IN,
				       syn_dev_callback, dev);
	return 0;
}

static void syn_removed(struct tcmu_device *dev)
{
	syn_dev_t *s = tcmu_dev_get_private(dev);
	tcmu_dbg("removed %s\n", tcmu_dev_get_cfgstring(dev));
	g_source_remove(s->watcher_id);
	g_io_channel_unref(s->gio);
	g_free(s);
}

struct tcmulib_handler syn_handler = {
	.name = "syn",
	.subtype = "syn",
	.cfg_desc = "valid options:\n"
		    "null: a nop storage where R/W requests are completed "
		    "immediately, like the null_blk device.",
	.added = syn_added,
	.removed = syn_removed,
};

gboolean tcmulib_callback(GIOChannel *source,
			  GIOCondition condition,
			  gpointer data)
{
	struct tcmulib_context *ctx = data;

	tcmu_dbg("master fd ready\n");
	tcmulib_master_fd_ready(ctx);

	return TRUE;
}

static void usage(void) {
	printf("\nusage:\n");
	printf("\ttcmu-synthesizer [options]\n");
	printf("\noptions:\n");
	printf("\t-h, --help: print this message and exit\n");
	printf("\t-V, --version: print version and exit\n");
	printf("\t-d, --debug: enable debug messages\n");
	printf("\n");
}

static struct option long_options[] = {
	{"debug", no_argument, 0, 'd'},
	{"help", no_argument, 0, 'h'},
	{"version", no_argument, 0, 'V'},
	{0, 0, 0, 0},
};

int main(int argc, char **argv)
{
	GMainLoop *loop;
	GIOChannel *libtcmu_gio;
	struct tcmulib_context *ctx;

	while (1) {
		int c;
		int option_index = 0;

		c = getopt_long(argc, argv, "dhV",
				long_options, &option_index);
		if (c == -1)
			break;

		switch (c) {
		case 'd':
			tcmu_set_log_level(TCMU_CONF_LOG_DEBUG);
			break;
		case 'V':
			printf("tcmu-synthesizer %s\n", TCMUR_VERSION);
			exit(1);
		default:
		case 'h':
			usage();
			exit(1);
		}
	}

	if (tcmu_setup_log(LOG_DIR)) {
		fprintf(stderr, "Could not setup tcmu logger.\n");
		exit(1);
	}

	ctx = tcmulib_initialize(&syn_handler, 1);
	if (!ctx) {
		tcmu_err("tcmulib_initialize failed\n");
		tcmu_destroy_log();
		exit(1);
	}

	tcmulib_register(ctx);
	/* Set up event for libtcmu */
	libtcmu_gio = g_io_channel_unix_new(tcmulib_get_master_fd(ctx));
	g_io_add_watch(libtcmu_gio, G_IO_IN, tcmulib_callback, ctx);
	loop = g_main_loop_new(NULL, FALSE);
	g_main_loop_run(loop);
	g_main_loop_unref(loop);
	tcmu_destroy_log();
	return 0;
}