Commit ec5cf8a2 authored by Ziye Yang's avatar Ziye Yang Committed by Daniel Verkamp
Browse files

bdev/iSCSI: Make the connection connect in async mode.



Change-Id: I9d3b56ed908273c6853014241a28237f8d077cfa
Signed-off-by: default avatarZiye Yang <optimistyzy@gmail.com>
Reviewed-on: https://review.gerrithub.io/405537


Tested-by: default avatarSPDK Automated Test System <sys_sgsw@intel.com>
Reviewed-by: default avatarJim Harris <james.r.harris@intel.com>
Reviewed-by: default avatarDaniel Verkamp <daniel.verkamp@intel.com>
parent 3ed91561
Loading
Loading
Loading
Loading
+150 −19
Original line number Diff line number Diff line
@@ -55,6 +55,10 @@ struct bdev_iscsi_lun;

static int bdev_iscsi_initialize(void);
static TAILQ_HEAD(, bdev_iscsi_lun) g_iscsi_lun_head = TAILQ_HEAD_INITIALIZER(g_iscsi_lun_head);
static TAILQ_HEAD(, bdev_iscsi_conn_req) g_iscsi_conn_req = TAILQ_HEAD_INITIALIZER(
			g_iscsi_conn_req);
static struct spdk_poller *g_conn_poller = NULL;
static bool g_module_is_initialized;

struct bdev_iscsi_io {
	struct spdk_thread *submit_td;
@@ -82,15 +86,30 @@ struct bdev_iscsi_io_channel {
	struct bdev_iscsi_lun	*lun;
};

struct bdev_iscsi_conn_req {
	struct iscsi_url			*url;
	char					*bdev_name;
	struct iscsi_context			*context;
	TAILQ_ENTRY(bdev_iscsi_conn_req)	link;
};

static int
bdev_iscsi_get_ctx_size(void)
{
	return sizeof(struct bdev_iscsi_io);
}

static void
bdev_iscsi_remove_conn_req(struct bdev_iscsi_conn_req *req)
{
	TAILQ_REMOVE(&g_iscsi_conn_req, req, link);
	free(req);
}

static void bdev_iscsi_finish(void)
{
	struct bdev_iscsi_lun *lun;
	struct bdev_iscsi_conn_req *req, *tmp;

	while (!TAILQ_EMPTY(&g_iscsi_lun_head)) {
		lun = TAILQ_FIRST(&g_iscsi_lun_head);
@@ -99,6 +118,14 @@ static void bdev_iscsi_finish(void)
		iscsi_destroy_context(lun->context);
		iscsi_destroy_url(lun->url);
	}

	TAILQ_FOREACH_SAFE(req, &g_iscsi_conn_req, link, tmp) {
		bdev_iscsi_remove_conn_req(req);
	}

	if (g_conn_poller) {
		spdk_poller_unregister(&g_conn_poller);
	}
}

static struct spdk_bdev_module g_iscsi_bdev_module = {
@@ -106,6 +133,7 @@ static struct spdk_bdev_module g_iscsi_bdev_module = {
	.module_init	= bdev_iscsi_initialize,
	.module_fini	= bdev_iscsi_finish,
	.get_ctx_size	= bdev_iscsi_get_ctx_size,
	.async_init	= true,
};

SPDK_BDEV_MODULE_REGISTER(&g_iscsi_bdev_module);
@@ -218,7 +246,7 @@ bdev_iscsi_poll(void *arg)
{
	struct bdev_iscsi_io_channel *ch = arg;
	struct bdev_iscsi_lun *lun = ch->lun;
	struct pollfd pfd;
	struct pollfd pfd = {};

	pfd.fd = iscsi_get_fd(lun->context);
	pfd.events = iscsi_which_events(lun->context);
@@ -426,20 +454,123 @@ error_return:
	return NULL;
}

static struct bdev_iscsi_conn_req *
bdev_iscsi_allocate_conn_req(struct iscsi_context *context, char *bdev_name, struct iscsi_url *url)
{
	struct bdev_iscsi_conn_req *req;

	req = calloc(1, sizeof(struct bdev_iscsi_conn_req));
	if (!req) {
		SPDK_ERRLOG("Cannot allocate pointer of struct bdev_iscsi_conn_req\n");
		return NULL;
	}

	req->bdev_name = bdev_name;
	req->url = url;
	req->context = context;

	return req;
}

static void
_bdev_iscsi_set_module_init(void)
{
	spdk_bdev_module_init_done(&g_iscsi_bdev_module);
	g_module_is_initialized = true;
}

static void
bdev_iscsi_set_module_init(void)
{
	if (!g_module_is_initialized && TAILQ_EMPTY(&g_iscsi_conn_req)) {
		_bdev_iscsi_set_module_init();
	}
}

static void
iscsi_readcapacity16_cb(struct iscsi_context *iscsi, int status,
			void *command_data, void *private_data)
{
	struct bdev_iscsi_conn_req *req = private_data;
	struct scsi_readcapacity16 *readcap16;
	struct spdk_bdev *bdev;
	struct scsi_task *task = command_data;

	if (status != SPDK_SCSI_STATUS_GOOD) {
		goto ret;
	}

	readcap16 = scsi_datain_unmarshall(task);
	bdev = create_iscsi_lun(req->context, req->url, req->bdev_name,
				readcap16->returned_lba + 1, readcap16->block_length);
	if (!bdev) {
		SPDK_ERRLOG("Unable to create iscsi bdev\n");
	}

ret:
	scsi_free_scsi_task(task);
	bdev_iscsi_remove_conn_req(req);
	bdev_iscsi_set_module_init();
}

static void
iscsi_connect_cb(struct iscsi_context *iscsi, int status,
		 void *command_data, void *private_data)
{
	struct bdev_iscsi_conn_req *req = private_data;
	struct scsi_task *task;

	if (status != SPDK_SCSI_STATUS_GOOD) {
		goto ret;
	}

	task = iscsi_readcapacity16_task(iscsi, 0, iscsi_readcapacity16_cb, req);
	if (task) {
		return;
	}
ret:
	bdev_iscsi_remove_conn_req(req);
	bdev_iscsi_set_module_init();
}

static int
iscsi_bdev_conn_poll(void *arg)
{
	struct bdev_iscsi_conn_req *req, *tmp;
	struct pollfd pfd;

	TAILQ_FOREACH_SAFE(req, &g_iscsi_conn_req, link, tmp) {
		pfd.fd = iscsi_get_fd(req->context);
		pfd.events = iscsi_which_events(req->context);
		pfd.revents = 0;
		if (poll(&pfd, 1, 0) < 0) {
			SPDK_ERRLOG("poll failed\n");
			return -1;
		}

		if (pfd.revents != 0) {
			if (iscsi_service(req->context, pfd.revents) < 0) {
				SPDK_ERRLOG("iscsi_service failed: %s\n", iscsi_get_error(req->context));
			}
		}
	}

	return 0;
}

static int
bdev_iscsi_initialize(void)
{
	struct spdk_conf_section *sp;
	struct iscsi_context *context;
	struct iscsi_url *url;
	struct spdk_bdev *bdev;
	struct scsi_task *task;
	struct scsi_readcapacity16 *readcap16;
	char *val, *bdev_name, *initiator_iqn;
	struct bdev_iscsi_conn_req *req;
	int i, rc;

	sp = spdk_conf_find_section(NULL, "iSCSI_Initiator");
	if (sp == NULL) {
		_bdev_iscsi_set_module_init();
		return 0;
	}

@@ -473,28 +604,28 @@ bdev_iscsi_initialize(void)
			break;
		}

		iscsi_set_session_type(context, ISCSI_SESSION_NORMAL);
		iscsi_set_header_digest(context, ISCSI_HEADER_DIGEST_NONE);
		rc = iscsi_full_connect_sync(context, url->portal, url->lun);
		if (rc != 0) {
			SPDK_ERRLOG("could not login\n");
			break;
		req = bdev_iscsi_allocate_conn_req(context, bdev_name, url);
		if (!req) {
			_bdev_iscsi_set_module_init();
			return -1;
		}

		task = iscsi_readcapacity16_sync(context, 0);
		readcap16 = scsi_datain_unmarshall(task);
		scsi_free_scsi_task(task);

		bdev = create_iscsi_lun(context, url, bdev_name,
					readcap16->returned_lba + 1, readcap16->block_length);
		if (!bdev) {
			SPDK_ERRLOG("Unable to create iscsi bdev\n");
			break;
		iscsi_set_session_type(context, ISCSI_SESSION_NORMAL);
		iscsi_set_header_digest(context, ISCSI_HEADER_DIGEST_NONE);
		rc = iscsi_full_connect_async(context, url->portal, url->lun, iscsi_connect_cb, req);
		if (rc < 0) {
			free(req);
			SPDK_ERRLOG("Failed to connect provided URL=%s, will ignore it\n", val);
			continue;
		}

		TAILQ_INSERT_TAIL(&g_iscsi_conn_req, req, link);
		i++;
	}

	if (!TAILQ_EMPTY(&g_iscsi_conn_req)) {
		g_conn_poller = spdk_poller_register(iscsi_bdev_conn_poll, NULL, 0);
	}
	return 0;
}