xref: /spdk/module/bdev/iscsi/bdev_iscsi.c (revision 746549cfe66596ea6cc8bc4f98a422d69d5980b0)
1488570ebSJim Harris /*   SPDX-License-Identifier: BSD-3-Clause
2a6dbe372Spaul luse  *   Copyright (C) 2017 Intel Corporation.
307fe6a43SSeth Howell  *   All rights reserved.
407fe6a43SSeth Howell  */
507fe6a43SSeth Howell 
607fe6a43SSeth Howell #include "spdk/stdinc.h"
707fe6a43SSeth Howell 
807fe6a43SSeth Howell #include "spdk/bdev.h"
907fe6a43SSeth Howell #include "spdk/env.h"
1007fe6a43SSeth Howell #include "spdk/fd.h"
1107fe6a43SSeth Howell #include "spdk/thread.h"
1207fe6a43SSeth Howell #include "spdk/json.h"
1307fe6a43SSeth Howell #include "spdk/util.h"
1407fe6a43SSeth Howell #include "spdk/rpc.h"
1507fe6a43SSeth Howell #include "spdk/string.h"
1607fe6a43SSeth Howell #include "spdk/iscsi_spec.h"
1707fe6a43SSeth Howell 
184e8e97c8STomasz Zawadzki #include "spdk/log.h"
1907fe6a43SSeth Howell #include "spdk/bdev_module.h"
2007fe6a43SSeth Howell 
2107fe6a43SSeth Howell #include "iscsi/iscsi.h"
2207fe6a43SSeth Howell #include "iscsi/scsi-lowlevel.h"
2307fe6a43SSeth Howell 
2407fe6a43SSeth Howell #include "bdev_iscsi.h"
2507fe6a43SSeth Howell 
2607fe6a43SSeth Howell struct bdev_iscsi_lun;
2707fe6a43SSeth Howell 
2807fe6a43SSeth Howell #define BDEV_ISCSI_CONNECTION_POLL_US 500 /* 0.5 ms */
2957de009aSJim Harris #define BDEV_ISCSI_NO_MAIN_CH_POLL_US 10000 /* 10ms */
3007fe6a43SSeth Howell 
311519aa47Sgongwei #define BDEV_ISCSI_TIMEOUT_POLL_PERIOD_DEFAULT	1000000ULL /* 1 s */
321519aa47Sgongwei #define BDEV_ISCSI_TIMEOUT_DEFAULT 30 /* 30 s */
331519aa47Sgongwei #define BDEV_ISCSI_TIMEOUT_POLL_PERIOD_DIVISOR 30
341519aa47Sgongwei 
3507fe6a43SSeth Howell #define DEFAULT_INITIATOR_NAME "iqn.2016-06.io.spdk:init"
3607fe6a43SSeth Howell 
372594e757SChangpeng Liu /* MAXIMUM UNMAP LBA COUNT:
382594e757SChangpeng Liu  * indicates the maximum  number of LBAs that may be unmapped
392594e757SChangpeng Liu  * by an UNMAP command.
402594e757SChangpeng Liu  */
412594e757SChangpeng Liu #define BDEV_ISCSI_DEFAULT_MAX_UNMAP_LBA_COUNT (32768)
422594e757SChangpeng Liu 
43b885e23bSChangpeng Liu /* MAXIMUM UNMAP BLOCK DESCRIPTOR COUNT:
44b885e23bSChangpeng Liu  * indicates the maximum number of UNMAP block descriptors that
45b885e23bSChangpeng Liu  * shall be contained in the parameter data transferred to the
46b885e23bSChangpeng Liu  * device server for an UNMAP command.
47b885e23bSChangpeng Liu  */
48b885e23bSChangpeng Liu #define BDEV_ISCSI_MAX_UNMAP_BLOCK_DESCS_COUNT (1)
49b885e23bSChangpeng Liu 
5007fe6a43SSeth Howell static int bdev_iscsi_initialize(void);
516b7e9d0aSGangCao static void bdev_iscsi_readcapacity16(struct iscsi_context *context, struct bdev_iscsi_lun *lun);
526b7e9d0aSGangCao static void _bdev_iscsi_submit_request(void *_bdev_io);
536b7e9d0aSGangCao 
5407fe6a43SSeth Howell static TAILQ_HEAD(, bdev_iscsi_conn_req) g_iscsi_conn_req = TAILQ_HEAD_INITIALIZER(
5507fe6a43SSeth Howell 			g_iscsi_conn_req);
5607fe6a43SSeth Howell static struct spdk_poller *g_conn_poller = NULL;
5707fe6a43SSeth Howell 
5807fe6a43SSeth Howell struct bdev_iscsi_io {
5907fe6a43SSeth Howell 	struct spdk_thread *submit_td;
606b7e9d0aSGangCao 	struct bdev_iscsi_lun *lun;
6107fe6a43SSeth Howell 	enum spdk_bdev_io_status status;
6207fe6a43SSeth Howell 	int scsi_status;
6307fe6a43SSeth Howell 	enum spdk_scsi_sense sk;
6407fe6a43SSeth Howell 	uint8_t asc;
6507fe6a43SSeth Howell 	uint8_t ascq;
6607fe6a43SSeth Howell };
6707fe6a43SSeth Howell 
6807fe6a43SSeth Howell struct bdev_iscsi_lun {
6907fe6a43SSeth Howell 	struct spdk_bdev		bdev;
7007fe6a43SSeth Howell 	struct iscsi_context		*context;
7107fe6a43SSeth Howell 	char				*initiator_iqn;
7207fe6a43SSeth Howell 	int				lun_id;
7307fe6a43SSeth Howell 	char				*url;
7407fe6a43SSeth Howell 	pthread_mutex_t			mutex;
7507fe6a43SSeth Howell 	uint32_t			ch_count;
7657de009aSJim Harris 	struct spdk_thread		*main_td;
7757de009aSJim Harris 	struct spdk_poller		*no_main_ch_poller;
7857de009aSJim Harris 	struct spdk_thread		*no_main_ch_poller_td;
7907fe6a43SSeth Howell 	bool				unmap_supported;
80b885e23bSChangpeng Liu 	uint32_t			max_unmap;
8107fe6a43SSeth Howell 	struct spdk_poller		*poller;
821519aa47Sgongwei 	struct spdk_poller		*timeout_poller;
8307fe6a43SSeth Howell };
8407fe6a43SSeth Howell 
8507fe6a43SSeth Howell struct bdev_iscsi_io_channel {
8607fe6a43SSeth Howell 	struct bdev_iscsi_lun	*lun;
8707fe6a43SSeth Howell };
8807fe6a43SSeth Howell 
8907fe6a43SSeth Howell struct bdev_iscsi_conn_req {
9007fe6a43SSeth Howell 	char					*url;
9107fe6a43SSeth Howell 	char					*bdev_name;
9207fe6a43SSeth Howell 	char					*initiator_iqn;
9307fe6a43SSeth Howell 	struct iscsi_context			*context;
9407fe6a43SSeth Howell 	spdk_bdev_iscsi_create_cb		create_cb;
9507fe6a43SSeth Howell 	void					*create_cb_arg;
9607fe6a43SSeth Howell 	bool					unmap_supported;
972594e757SChangpeng Liu 	uint32_t				max_unmap;
9807fe6a43SSeth Howell 	int					lun;
9907fe6a43SSeth Howell 	int					status;
10007fe6a43SSeth Howell 	TAILQ_ENTRY(bdev_iscsi_conn_req)	link;
10107fe6a43SSeth Howell };
10207fe6a43SSeth Howell 
1031519aa47Sgongwei static struct spdk_bdev_iscsi_opts g_opts = {
104c8e594c2Sgongwei 	.timeout_sec = BDEV_ISCSI_TIMEOUT_DEFAULT,
1051519aa47Sgongwei 	.timeout_poller_period_us = BDEV_ISCSI_TIMEOUT_POLL_PERIOD_DEFAULT,
1061519aa47Sgongwei };
1071519aa47Sgongwei 
1081519aa47Sgongwei void
bdev_iscsi_get_opts(struct spdk_bdev_iscsi_opts * opts)1091519aa47Sgongwei bdev_iscsi_get_opts(struct spdk_bdev_iscsi_opts *opts)
1101519aa47Sgongwei {
1111519aa47Sgongwei 	*opts = g_opts;
1121519aa47Sgongwei }
1131519aa47Sgongwei 
1141519aa47Sgongwei int
bdev_iscsi_set_opts(struct spdk_bdev_iscsi_opts * opts)1151519aa47Sgongwei bdev_iscsi_set_opts(struct spdk_bdev_iscsi_opts *opts)
1161519aa47Sgongwei {
1171519aa47Sgongwei 	/* make the poller period equal to timeout / 30 */
118c8e594c2Sgongwei 	opts->timeout_poller_period_us = (opts->timeout_sec * 1000000ULL) /
1191519aa47Sgongwei 					 BDEV_ISCSI_TIMEOUT_POLL_PERIOD_DIVISOR;
1201519aa47Sgongwei 
1211519aa47Sgongwei 	g_opts = *opts;
1221519aa47Sgongwei 
1231519aa47Sgongwei 	return 0;
1241519aa47Sgongwei }
1251519aa47Sgongwei 
12607fe6a43SSeth Howell static void
complete_conn_req(struct bdev_iscsi_conn_req * req,struct spdk_bdev * bdev,int status)12707fe6a43SSeth Howell complete_conn_req(struct bdev_iscsi_conn_req *req, struct spdk_bdev *bdev,
12807fe6a43SSeth Howell 		  int status)
12907fe6a43SSeth Howell {
13007fe6a43SSeth Howell 	TAILQ_REMOVE(&g_iscsi_conn_req, req, link);
13107fe6a43SSeth Howell 	req->create_cb(req->create_cb_arg, bdev, status);
13207fe6a43SSeth Howell 
13307fe6a43SSeth Howell 	/*
13407fe6a43SSeth Howell 	 * we are still running in the context of iscsi_service()
13507fe6a43SSeth Howell 	 * so do not tear down its data structures here
13607fe6a43SSeth Howell 	 */
13707fe6a43SSeth Howell 	req->status = status;
13807fe6a43SSeth Howell }
13907fe6a43SSeth Howell 
14007fe6a43SSeth Howell static int
bdev_iscsi_get_ctx_size(void)14107fe6a43SSeth Howell bdev_iscsi_get_ctx_size(void)
14207fe6a43SSeth Howell {
14307fe6a43SSeth Howell 	return sizeof(struct bdev_iscsi_io);
14407fe6a43SSeth Howell }
14507fe6a43SSeth Howell 
14607fe6a43SSeth Howell static void
_iscsi_free_lun(void * arg)14707fe6a43SSeth Howell _iscsi_free_lun(void *arg)
14807fe6a43SSeth Howell {
14907fe6a43SSeth Howell 	struct bdev_iscsi_lun *lun = arg;
15007fe6a43SSeth Howell 
15107fe6a43SSeth Howell 	assert(lun != NULL);
15207fe6a43SSeth Howell 	iscsi_destroy_context(lun->context);
15307fe6a43SSeth Howell 	pthread_mutex_destroy(&lun->mutex);
15407fe6a43SSeth Howell 	free(lun->bdev.name);
15507fe6a43SSeth Howell 	free(lun->url);
15607fe6a43SSeth Howell 	free(lun->initiator_iqn);
15707fe6a43SSeth Howell 
15807fe6a43SSeth Howell 	spdk_bdev_destruct_done(&lun->bdev, 0);
15907fe6a43SSeth Howell 	free(lun);
16007fe6a43SSeth Howell }
16107fe6a43SSeth Howell 
16207fe6a43SSeth Howell static void
_bdev_iscsi_conn_req_free(struct bdev_iscsi_conn_req * req)16307fe6a43SSeth Howell _bdev_iscsi_conn_req_free(struct bdev_iscsi_conn_req *req)
16407fe6a43SSeth Howell {
16507fe6a43SSeth Howell 	free(req->initiator_iqn);
16607fe6a43SSeth Howell 	free(req->bdev_name);
16707fe6a43SSeth Howell 	free(req->url);
16807fe6a43SSeth Howell 	/* destroy will call iscsi_disconnect() implicitly if connected */
16907fe6a43SSeth Howell 	iscsi_destroy_context(req->context);
17007fe6a43SSeth Howell 	free(req);
17107fe6a43SSeth Howell }
17207fe6a43SSeth Howell 
17307fe6a43SSeth Howell static void
bdev_iscsi_finish(void)17407fe6a43SSeth Howell bdev_iscsi_finish(void)
17507fe6a43SSeth Howell {
17607fe6a43SSeth Howell 	struct bdev_iscsi_conn_req *req, *tmp;
17707fe6a43SSeth Howell 
17807fe6a43SSeth Howell 	/* clear out pending connection requests here. We cannot
17907fe6a43SSeth Howell 	 * simply set the state to a non SCSI_STATUS_GOOD state as
1803f912cf0SMichal Berger 	 * the connection poller won't run anymore
18107fe6a43SSeth Howell 	 */
18207fe6a43SSeth Howell 	TAILQ_FOREACH_SAFE(req, &g_iscsi_conn_req, link, tmp) {
18307fe6a43SSeth Howell 		_bdev_iscsi_conn_req_free(req);
18407fe6a43SSeth Howell 	}
18507fe6a43SSeth Howell 
18607fe6a43SSeth Howell 	if (g_conn_poller) {
18707fe6a43SSeth Howell 		spdk_poller_unregister(&g_conn_poller);
18807fe6a43SSeth Howell 	}
18907fe6a43SSeth Howell }
19007fe6a43SSeth Howell 
1916f445382Sgongwei static void
bdev_iscsi_opts_config_json(struct spdk_json_write_ctx * w)1926f445382Sgongwei bdev_iscsi_opts_config_json(struct spdk_json_write_ctx *w)
1936f445382Sgongwei {
1946f445382Sgongwei 	spdk_json_write_object_begin(w);
1956f445382Sgongwei 
1966f445382Sgongwei 	spdk_json_write_named_string(w, "method", "bdev_iscsi_set_options");
1976f445382Sgongwei 
1986f445382Sgongwei 	spdk_json_write_named_object_begin(w, "params");
1996f445382Sgongwei 	spdk_json_write_named_uint64(w, "timeout_sec", g_opts.timeout_sec);
2006f445382Sgongwei 	spdk_json_write_object_end(w);
2016f445382Sgongwei 
2026f445382Sgongwei 	spdk_json_write_object_end(w);
2036f445382Sgongwei }
2046f445382Sgongwei 
2056f445382Sgongwei static int
bdev_iscsi_config_json(struct spdk_json_write_ctx * w)2066f445382Sgongwei bdev_iscsi_config_json(struct spdk_json_write_ctx *w)
2076f445382Sgongwei {
2086f445382Sgongwei 	bdev_iscsi_opts_config_json(w);
2096f445382Sgongwei 	return 0;
2106f445382Sgongwei }
2116f445382Sgongwei 
21207fe6a43SSeth Howell static struct spdk_bdev_module g_iscsi_bdev_module = {
21307fe6a43SSeth Howell 	.name		= "iscsi",
21407fe6a43SSeth Howell 	.module_init	= bdev_iscsi_initialize,
21507fe6a43SSeth Howell 	.module_fini	= bdev_iscsi_finish,
2166f445382Sgongwei 	.config_json	= bdev_iscsi_config_json,
21707fe6a43SSeth Howell 	.get_ctx_size	= bdev_iscsi_get_ctx_size,
21807fe6a43SSeth Howell };
21907fe6a43SSeth Howell 
22007fe6a43SSeth Howell SPDK_BDEV_MODULE_REGISTER(iscsi, &g_iscsi_bdev_module);
22107fe6a43SSeth Howell 
22207fe6a43SSeth Howell static void
_bdev_iscsi_io_complete(void * _iscsi_io)22307fe6a43SSeth Howell _bdev_iscsi_io_complete(void *_iscsi_io)
22407fe6a43SSeth Howell {
22507fe6a43SSeth Howell 	struct bdev_iscsi_io *iscsi_io = _iscsi_io;
22607fe6a43SSeth Howell 
22707fe6a43SSeth Howell 	if (iscsi_io->status == SPDK_BDEV_IO_STATUS_SUCCESS) {
22807fe6a43SSeth Howell 		spdk_bdev_io_complete_scsi_status(spdk_bdev_io_from_ctx(iscsi_io), iscsi_io->scsi_status,
22907fe6a43SSeth Howell 						  iscsi_io->sk, iscsi_io->asc, iscsi_io->ascq);
23007fe6a43SSeth Howell 	} else {
23107fe6a43SSeth Howell 		spdk_bdev_io_complete(spdk_bdev_io_from_ctx(iscsi_io), iscsi_io->status);
23207fe6a43SSeth Howell 	}
23307fe6a43SSeth Howell }
23407fe6a43SSeth Howell 
23507fe6a43SSeth Howell static void
bdev_iscsi_io_complete(struct bdev_iscsi_io * iscsi_io,enum spdk_bdev_io_status status)23607fe6a43SSeth Howell bdev_iscsi_io_complete(struct bdev_iscsi_io *iscsi_io, enum spdk_bdev_io_status status)
23707fe6a43SSeth Howell {
23807fe6a43SSeth Howell 	iscsi_io->status = status;
23907fe6a43SSeth Howell 	if (iscsi_io->submit_td != NULL) {
24007fe6a43SSeth Howell 		spdk_thread_send_msg(iscsi_io->submit_td, _bdev_iscsi_io_complete, iscsi_io);
24107fe6a43SSeth Howell 	} else {
24207fe6a43SSeth Howell 		_bdev_iscsi_io_complete(iscsi_io);
24307fe6a43SSeth Howell 	}
24407fe6a43SSeth Howell }
24507fe6a43SSeth Howell 
2466b7e9d0aSGangCao static bool
_bdev_iscsi_is_size_change(int status,struct scsi_task * task)2476b7e9d0aSGangCao _bdev_iscsi_is_size_change(int status, struct scsi_task *task)
2486b7e9d0aSGangCao {
2496b7e9d0aSGangCao 	if (status == SPDK_SCSI_STATUS_CHECK_CONDITION &&
2506b7e9d0aSGangCao 	    (uint8_t)task->sense.key == SPDK_SCSI_SENSE_UNIT_ATTENTION &&
2516b7e9d0aSGangCao 	    task->sense.ascq == 0x2a09) {
2526b7e9d0aSGangCao 		/* ASCQ: SCSI_SENSE_ASCQ_CAPACITY_DATA_HAS_CHANGED (0x2a09) */
2536b7e9d0aSGangCao 		return true;
2546b7e9d0aSGangCao 	}
2556b7e9d0aSGangCao 
2566b7e9d0aSGangCao 	return false;
2576b7e9d0aSGangCao }
2586b7e9d0aSGangCao 
25907fe6a43SSeth Howell /* Common call back function for read/write/flush command */
26007fe6a43SSeth Howell static void
bdev_iscsi_command_cb(struct iscsi_context * context,int status,void * _task,void * _iscsi_io)26107fe6a43SSeth Howell bdev_iscsi_command_cb(struct iscsi_context *context, int status, void *_task, void *_iscsi_io)
26207fe6a43SSeth Howell {
26307fe6a43SSeth Howell 	struct scsi_task *task = _task;
26407fe6a43SSeth Howell 	struct bdev_iscsi_io *iscsi_io = _iscsi_io;
2656b7e9d0aSGangCao 	struct spdk_bdev_io *bdev_io;
26607fe6a43SSeth Howell 
26707fe6a43SSeth Howell 	iscsi_io->scsi_status = status;
26807fe6a43SSeth Howell 	iscsi_io->sk = (uint8_t)task->sense.key;
26907fe6a43SSeth Howell 	iscsi_io->asc = (task->sense.ascq >> 8) & 0xFF;
27007fe6a43SSeth Howell 	iscsi_io->ascq = task->sense.ascq & 0xFF;
27107fe6a43SSeth Howell 
2726b7e9d0aSGangCao 	if (_bdev_iscsi_is_size_change(status, task)) {
2736b7e9d0aSGangCao 		bdev_iscsi_readcapacity16(context, iscsi_io->lun);
2746b7e9d0aSGangCao 
2756b7e9d0aSGangCao 		/* Retry this failed IO immediately */
2766b7e9d0aSGangCao 		bdev_io = spdk_bdev_io_from_ctx(iscsi_io);
2776b7e9d0aSGangCao 		if (iscsi_io->submit_td != NULL) {
2786b7e9d0aSGangCao 			spdk_thread_send_msg(iscsi_io->lun->main_td,
2796b7e9d0aSGangCao 					     _bdev_iscsi_submit_request, bdev_io);
2806b7e9d0aSGangCao 		} else {
2816b7e9d0aSGangCao 			_bdev_iscsi_submit_request(bdev_io);
2826b7e9d0aSGangCao 		}
2836b7e9d0aSGangCao 	} else {
28407fe6a43SSeth Howell 		bdev_iscsi_io_complete(iscsi_io, SPDK_BDEV_IO_STATUS_SUCCESS);
28507fe6a43SSeth Howell 	}
286c161969dSJim Harris 
287c161969dSJim Harris 	scsi_free_scsi_task(task);
2886b7e9d0aSGangCao }
2896b7e9d0aSGangCao 
2906b7e9d0aSGangCao static int
bdev_iscsi_resize(struct spdk_bdev * bdev,const uint64_t new_size_in_block)2916b7e9d0aSGangCao bdev_iscsi_resize(struct spdk_bdev *bdev, const uint64_t new_size_in_block)
2926b7e9d0aSGangCao {
2936b7e9d0aSGangCao 	int rc;
2946b7e9d0aSGangCao 
2956b7e9d0aSGangCao 	assert(bdev->module == &g_iscsi_bdev_module);
2966b7e9d0aSGangCao 
2976b7e9d0aSGangCao 	if (new_size_in_block <= bdev->blockcnt) {
2986b7e9d0aSGangCao 		SPDK_ERRLOG("The new bdev size must be larger than current bdev size.\n");
2996b7e9d0aSGangCao 		return -EINVAL;
3006b7e9d0aSGangCao 	}
3016b7e9d0aSGangCao 
3026b7e9d0aSGangCao 	rc = spdk_bdev_notify_blockcnt_change(bdev, new_size_in_block);
3036b7e9d0aSGangCao 	if (rc != 0) {
3046b7e9d0aSGangCao 		SPDK_ERRLOG("failed to notify block cnt change.\n");
3056b7e9d0aSGangCao 		return rc;
3066b7e9d0aSGangCao 	}
3076b7e9d0aSGangCao 
3086b7e9d0aSGangCao 	return 0;
3096b7e9d0aSGangCao }
3106b7e9d0aSGangCao 
3116b7e9d0aSGangCao static void
bdev_iscsi_readcapacity16_cb(struct iscsi_context * context,int status,void * _task,void * private_data)3126b7e9d0aSGangCao bdev_iscsi_readcapacity16_cb(struct iscsi_context *context, int status, void *_task,
3136b7e9d0aSGangCao 			     void *private_data)
3146b7e9d0aSGangCao {
3156b7e9d0aSGangCao 	struct bdev_iscsi_lun *lun = private_data;
3166b7e9d0aSGangCao 	struct scsi_readcapacity16 *readcap16;
3176b7e9d0aSGangCao 	struct scsi_task *task = _task;
3186b7e9d0aSGangCao 	uint64_t size_in_block = 0;
3196b7e9d0aSGangCao 	int rc;
3206b7e9d0aSGangCao 
3216b7e9d0aSGangCao 	if (status != SPDK_SCSI_STATUS_GOOD) {
3226b7e9d0aSGangCao 		SPDK_ERRLOG("iSCSI error: %s\n", iscsi_get_error(context));
3236b7e9d0aSGangCao 		goto ret;
3246b7e9d0aSGangCao 	}
3256b7e9d0aSGangCao 
3266b7e9d0aSGangCao 	readcap16 = scsi_datain_unmarshall(task);
3276b7e9d0aSGangCao 	if (!readcap16) {
3286b7e9d0aSGangCao 		SPDK_ERRLOG("Read capacity error\n");
3296b7e9d0aSGangCao 		goto ret;
3306b7e9d0aSGangCao 	}
3316b7e9d0aSGangCao 
3326b7e9d0aSGangCao 	size_in_block = readcap16->returned_lba + 1;
3336b7e9d0aSGangCao 
3346b7e9d0aSGangCao 	rc = bdev_iscsi_resize(&lun->bdev, size_in_block);
3356b7e9d0aSGangCao 	if (rc != 0) {
3366b7e9d0aSGangCao 		SPDK_ERRLOG("Bdev (%s) resize error: %d\n", lun->bdev.name, rc);
3376b7e9d0aSGangCao 	}
3386b7e9d0aSGangCao 
3396b7e9d0aSGangCao ret:
3406b7e9d0aSGangCao 	scsi_free_scsi_task(task);
3416b7e9d0aSGangCao }
3426b7e9d0aSGangCao 
3436b7e9d0aSGangCao static void
bdev_iscsi_readcapacity16(struct iscsi_context * context,struct bdev_iscsi_lun * lun)3446b7e9d0aSGangCao bdev_iscsi_readcapacity16(struct iscsi_context *context, struct bdev_iscsi_lun *lun)
3456b7e9d0aSGangCao {
3466b7e9d0aSGangCao 	struct scsi_task *task;
3476b7e9d0aSGangCao 
3486b7e9d0aSGangCao 	task = iscsi_readcapacity16_task(context, lun->lun_id,
3496b7e9d0aSGangCao 					 bdev_iscsi_readcapacity16_cb, lun);
3506b7e9d0aSGangCao 	if (task == NULL) {
3516b7e9d0aSGangCao 		SPDK_ERRLOG("failed to get readcapacity16_task\n");
3526b7e9d0aSGangCao 	}
3536b7e9d0aSGangCao }
35407fe6a43SSeth Howell 
35507fe6a43SSeth Howell static void
bdev_iscsi_readv(struct bdev_iscsi_lun * lun,struct bdev_iscsi_io * iscsi_io,struct iovec * iov,int iovcnt,uint64_t nbytes,uint64_t lba)35607fe6a43SSeth Howell bdev_iscsi_readv(struct bdev_iscsi_lun *lun, struct bdev_iscsi_io *iscsi_io,
35707fe6a43SSeth Howell 		 struct iovec *iov, int iovcnt, uint64_t nbytes, uint64_t lba)
35807fe6a43SSeth Howell {
35907fe6a43SSeth Howell 	struct scsi_task *task;
36007fe6a43SSeth Howell 
3612172c432STomasz Zawadzki 	SPDK_DEBUGLOG(iscsi_init, "read %d iovs size %lu to lba: %#lx\n",
36207fe6a43SSeth Howell 		      iovcnt, nbytes, lba);
36307fe6a43SSeth Howell 
36407fe6a43SSeth Howell 	task = iscsi_read16_task(lun->context, lun->lun_id, lba, nbytes, lun->bdev.blocklen, 0, 0, 0, 0, 0,
36507fe6a43SSeth Howell 				 bdev_iscsi_command_cb, iscsi_io);
36607fe6a43SSeth Howell 	if (task == NULL) {
36707fe6a43SSeth Howell 		SPDK_ERRLOG("failed to get read16_task\n");
36807fe6a43SSeth Howell 		bdev_iscsi_io_complete(iscsi_io, SPDK_BDEV_IO_STATUS_FAILED);
36907fe6a43SSeth Howell 		return;
37007fe6a43SSeth Howell 	}
37107fe6a43SSeth Howell 
37207fe6a43SSeth Howell #if defined(LIBISCSI_FEATURE_IOVECTOR)
37307fe6a43SSeth Howell 	scsi_task_set_iov_in(task, (struct scsi_iovec *)iov, iovcnt);
37407fe6a43SSeth Howell #else
37507fe6a43SSeth Howell 	int i;
37607fe6a43SSeth Howell 	for (i = 0; i < iovcnt; i++) {
37707fe6a43SSeth Howell 		scsi_task_add_data_in_buffer(task, iov[i].iov_len, iov[i].iov_base);
37807fe6a43SSeth Howell 	}
37907fe6a43SSeth Howell #endif
38007fe6a43SSeth Howell }
38107fe6a43SSeth Howell 
38207fe6a43SSeth Howell static void
bdev_iscsi_writev(struct bdev_iscsi_lun * lun,struct bdev_iscsi_io * iscsi_io,struct iovec * iov,int iovcnt,uint64_t nbytes,uint64_t lba)38307fe6a43SSeth Howell bdev_iscsi_writev(struct bdev_iscsi_lun *lun, struct bdev_iscsi_io *iscsi_io,
38407fe6a43SSeth Howell 		  struct iovec *iov, int iovcnt, uint64_t nbytes, uint64_t lba)
38507fe6a43SSeth Howell {
38607fe6a43SSeth Howell 	struct scsi_task *task;
38707fe6a43SSeth Howell 
3882172c432STomasz Zawadzki 	SPDK_DEBUGLOG(iscsi_init, "write %d iovs size %lu to lba: %#lx\n",
38907fe6a43SSeth Howell 		      iovcnt, nbytes, lba);
39007fe6a43SSeth Howell 
39107fe6a43SSeth Howell 	task = iscsi_write16_task(lun->context, lun->lun_id, lba, NULL, nbytes, lun->bdev.blocklen, 0, 0, 0,
39207fe6a43SSeth Howell 				  0, 0,
39307fe6a43SSeth Howell 				  bdev_iscsi_command_cb, iscsi_io);
39407fe6a43SSeth Howell 	if (task == NULL) {
39507fe6a43SSeth Howell 		SPDK_ERRLOG("failed to get write16_task\n");
39607fe6a43SSeth Howell 		bdev_iscsi_io_complete(iscsi_io, SPDK_BDEV_IO_STATUS_FAILED);
39707fe6a43SSeth Howell 		return;
39807fe6a43SSeth Howell 	}
39907fe6a43SSeth Howell 
40007fe6a43SSeth Howell #if defined(LIBISCSI_FEATURE_IOVECTOR)
40107fe6a43SSeth Howell 	scsi_task_set_iov_out(task, (struct scsi_iovec *)iov, iovcnt);
40207fe6a43SSeth Howell #else
40307fe6a43SSeth Howell 	int i;
40407fe6a43SSeth Howell 	for (i = 0; i < iovcnt; i++) {
40507fe6a43SSeth Howell 		scsi_task_add_data_in_buffer(task, iov[i].iov_len, iov[i].iov_base);
40607fe6a43SSeth Howell 	}
40707fe6a43SSeth Howell #endif
40807fe6a43SSeth Howell }
40907fe6a43SSeth Howell 
41007fe6a43SSeth Howell static void
bdev_iscsi_destruct_cb(void * ctx)41107fe6a43SSeth Howell bdev_iscsi_destruct_cb(void *ctx)
41207fe6a43SSeth Howell {
41307fe6a43SSeth Howell 	struct bdev_iscsi_lun *lun = ctx;
41407fe6a43SSeth Howell 
41557de009aSJim Harris 	spdk_poller_unregister(&lun->no_main_ch_poller);
41607fe6a43SSeth Howell 	spdk_io_device_unregister(lun, _iscsi_free_lun);
41707fe6a43SSeth Howell }
41807fe6a43SSeth Howell 
41907fe6a43SSeth Howell static int
bdev_iscsi_destruct(void * ctx)42007fe6a43SSeth Howell bdev_iscsi_destruct(void *ctx)
42107fe6a43SSeth Howell {
42207fe6a43SSeth Howell 	struct bdev_iscsi_lun *lun = ctx;
42307fe6a43SSeth Howell 
42457de009aSJim Harris 	assert(lun->no_main_ch_poller_td);
42557de009aSJim Harris 	spdk_thread_send_msg(lun->no_main_ch_poller_td, bdev_iscsi_destruct_cb, lun);
42607fe6a43SSeth Howell 	return 1;
42707fe6a43SSeth Howell }
42807fe6a43SSeth Howell 
42907fe6a43SSeth Howell static void
bdev_iscsi_flush(struct bdev_iscsi_lun * lun,struct bdev_iscsi_io * iscsi_io,uint32_t num_blocks,int immed,uint64_t lba)43007fe6a43SSeth Howell bdev_iscsi_flush(struct bdev_iscsi_lun *lun, struct bdev_iscsi_io *iscsi_io, uint32_t num_blocks,
43107fe6a43SSeth Howell 		 int immed, uint64_t lba)
43207fe6a43SSeth Howell {
43307fe6a43SSeth Howell 	struct scsi_task *task;
43407fe6a43SSeth Howell 
43507fe6a43SSeth Howell 	task = iscsi_synchronizecache16_task(lun->context, lun->lun_id, lba,
43607fe6a43SSeth Howell 					     num_blocks, 0, immed, bdev_iscsi_command_cb, iscsi_io);
43707fe6a43SSeth Howell 	if (task == NULL) {
43807fe6a43SSeth Howell 		SPDK_ERRLOG("failed to get sync16_task\n");
43907fe6a43SSeth Howell 		bdev_iscsi_io_complete(iscsi_io, SPDK_BDEV_IO_STATUS_FAILED);
44007fe6a43SSeth Howell 		return;
44107fe6a43SSeth Howell 	}
44207fe6a43SSeth Howell }
44307fe6a43SSeth Howell 
44407fe6a43SSeth Howell static void
bdev_iscsi_unmap(struct bdev_iscsi_lun * lun,struct bdev_iscsi_io * iscsi_io,uint64_t lba,uint64_t num_blocks)44507fe6a43SSeth Howell bdev_iscsi_unmap(struct bdev_iscsi_lun *lun, struct bdev_iscsi_io *iscsi_io,
44607fe6a43SSeth Howell 		 uint64_t lba, uint64_t num_blocks)
44707fe6a43SSeth Howell {
44807fe6a43SSeth Howell 	struct scsi_task *task;
449b885e23bSChangpeng Liu 	struct unmap_list list[BDEV_ISCSI_MAX_UNMAP_BLOCK_DESCS_COUNT] = {};
450b885e23bSChangpeng Liu 	struct unmap_list *entry;
451b885e23bSChangpeng Liu 	uint32_t num_unmap_list;
452b885e23bSChangpeng Liu 	uint64_t offset, remaining, unmap_blocks;
45307fe6a43SSeth Howell 
454b885e23bSChangpeng Liu 	num_unmap_list = spdk_divide_round_up(num_blocks, lun->max_unmap);
455b885e23bSChangpeng Liu 	if (num_unmap_list > BDEV_ISCSI_MAX_UNMAP_BLOCK_DESCS_COUNT) {
456b885e23bSChangpeng Liu 		SPDK_ERRLOG("Too many unmap entries\n");
457b885e23bSChangpeng Liu 		goto failed;
458b885e23bSChangpeng Liu 	}
459b885e23bSChangpeng Liu 
460b885e23bSChangpeng Liu 	remaining = num_blocks;
461b885e23bSChangpeng Liu 	offset = lba;
462b885e23bSChangpeng Liu 	num_unmap_list = 0;
463b885e23bSChangpeng Liu 	entry = &list[0];
464b885e23bSChangpeng Liu 
465b885e23bSChangpeng Liu 	do {
466b885e23bSChangpeng Liu 		unmap_blocks = spdk_min(remaining, lun->max_unmap);
467b885e23bSChangpeng Liu 		entry->lba = offset;
468b885e23bSChangpeng Liu 		entry->num = unmap_blocks;
469b885e23bSChangpeng Liu 		num_unmap_list++;
470b885e23bSChangpeng Liu 		remaining -= unmap_blocks;
471b885e23bSChangpeng Liu 		offset += unmap_blocks;
472b885e23bSChangpeng Liu 		entry++;
473b885e23bSChangpeng Liu 	} while (remaining > 0);
474b885e23bSChangpeng Liu 
4759b81235fSBin Yang 	task = iscsi_unmap_task(lun->context, lun->lun_id, 0, 0, list, num_unmap_list,
47607fe6a43SSeth Howell 				bdev_iscsi_command_cb, iscsi_io);
477b885e23bSChangpeng Liu 	if (task != NULL) {
47807fe6a43SSeth Howell 		return;
47907fe6a43SSeth Howell 	}
480b885e23bSChangpeng Liu 	SPDK_ERRLOG("failed to get unmap_task\n");
481b885e23bSChangpeng Liu 
482b885e23bSChangpeng Liu failed:
483b885e23bSChangpeng Liu 	bdev_iscsi_io_complete(iscsi_io, SPDK_BDEV_IO_STATUS_FAILED);
48407fe6a43SSeth Howell }
48507fe6a43SSeth Howell 
48607fe6a43SSeth Howell static void
bdev_iscsi_reset_cb(struct iscsi_context * context,int status,void * command_data,void * private_data)48707fe6a43SSeth Howell bdev_iscsi_reset_cb(struct iscsi_context *context __attribute__((unused)), int status,
48807fe6a43SSeth Howell 		    void *command_data, void *private_data)
48907fe6a43SSeth Howell {
49007fe6a43SSeth Howell 	uint32_t tmf_response;
49107fe6a43SSeth Howell 	struct bdev_iscsi_io *iscsi_io = private_data;
49207fe6a43SSeth Howell 
49307fe6a43SSeth Howell 	tmf_response = *(uint32_t *)command_data;
49407fe6a43SSeth Howell 	if (tmf_response == ISCSI_TASK_FUNC_RESP_COMPLETE) {
49507fe6a43SSeth Howell 		bdev_iscsi_io_complete(iscsi_io, SPDK_BDEV_IO_STATUS_SUCCESS);
49607fe6a43SSeth Howell 	} else {
49707fe6a43SSeth Howell 		bdev_iscsi_io_complete(iscsi_io, SPDK_BDEV_IO_STATUS_FAILED);
49807fe6a43SSeth Howell 	}
49907fe6a43SSeth Howell }
50007fe6a43SSeth Howell 
50107fe6a43SSeth Howell static void
_bdev_iscsi_reset(void * _bdev_io)50207fe6a43SSeth Howell _bdev_iscsi_reset(void *_bdev_io)
50307fe6a43SSeth Howell {
50407fe6a43SSeth Howell 	int rc;
50507fe6a43SSeth Howell 	struct spdk_bdev_io *bdev_io = _bdev_io;
50607fe6a43SSeth Howell 	struct bdev_iscsi_lun *lun = (struct bdev_iscsi_lun *)bdev_io->bdev->ctxt;
50707fe6a43SSeth Howell 	struct bdev_iscsi_io *iscsi_io = (struct bdev_iscsi_io *)bdev_io->driver_ctx;
50807fe6a43SSeth Howell 	struct iscsi_context *context = lun->context;
50907fe6a43SSeth Howell 
51007fe6a43SSeth Howell 	rc = iscsi_task_mgmt_lun_reset_async(context, lun->lun_id,
51107fe6a43SSeth Howell 					     bdev_iscsi_reset_cb, iscsi_io);
51207fe6a43SSeth Howell 	if (rc != 0) {
51307fe6a43SSeth Howell 		SPDK_ERRLOG("failed to do iscsi reset\n");
51407fe6a43SSeth Howell 		bdev_iscsi_io_complete(iscsi_io, SPDK_BDEV_IO_STATUS_FAILED);
51507fe6a43SSeth Howell 		return;
51607fe6a43SSeth Howell 	}
51707fe6a43SSeth Howell }
51807fe6a43SSeth Howell 
51907fe6a43SSeth Howell static void
bdev_iscsi_reset(struct spdk_bdev_io * bdev_io)52007fe6a43SSeth Howell bdev_iscsi_reset(struct spdk_bdev_io *bdev_io)
52107fe6a43SSeth Howell {
52207fe6a43SSeth Howell 	struct bdev_iscsi_lun *lun = (struct bdev_iscsi_lun *)bdev_io->bdev->ctxt;
52357de009aSJim Harris 	spdk_thread_send_msg(lun->main_td, _bdev_iscsi_reset, bdev_io);
52407fe6a43SSeth Howell }
52507fe6a43SSeth Howell 
52607fe6a43SSeth Howell static int
bdev_iscsi_poll_lun(void * _lun)52707fe6a43SSeth Howell bdev_iscsi_poll_lun(void *_lun)
52807fe6a43SSeth Howell {
52907fe6a43SSeth Howell 	struct bdev_iscsi_lun *lun = _lun;
53007fe6a43SSeth Howell 	struct pollfd pfd = {};
53107fe6a43SSeth Howell 
53207fe6a43SSeth Howell 	pfd.fd = iscsi_get_fd(lun->context);
53307fe6a43SSeth Howell 	pfd.events = iscsi_which_events(lun->context);
53407fe6a43SSeth Howell 
53507fe6a43SSeth Howell 	if (poll(&pfd, 1, 0) < 0) {
53607fe6a43SSeth Howell 		SPDK_ERRLOG("poll failed\n");
537eb05cbd6SMaciej Szwed 		return SPDK_POLLER_IDLE;
53807fe6a43SSeth Howell 	}
53907fe6a43SSeth Howell 
54007fe6a43SSeth Howell 	if (pfd.revents != 0) {
54107fe6a43SSeth Howell 		if (iscsi_service(lun->context, pfd.revents) < 0) {
54207fe6a43SSeth Howell 			SPDK_ERRLOG("iscsi_service failed: %s\n", iscsi_get_error(lun->context));
54307fe6a43SSeth Howell 		}
544eb05cbd6SMaciej Szwed 
545eb05cbd6SMaciej Szwed 		return SPDK_POLLER_BUSY;
54607fe6a43SSeth Howell 	}
54707fe6a43SSeth Howell 
548eb05cbd6SMaciej Szwed 	return SPDK_POLLER_IDLE;
54907fe6a43SSeth Howell }
55007fe6a43SSeth Howell 
55107fe6a43SSeth Howell static int
bdev_iscsi_poll_lun_timeout(void * _lun)5521519aa47Sgongwei bdev_iscsi_poll_lun_timeout(void *_lun)
5531519aa47Sgongwei {
5541519aa47Sgongwei 	struct bdev_iscsi_lun *lun = _lun;
5551519aa47Sgongwei 	/* passing 0 here to iscsi_service means do nothing except for timeout checks */
5561519aa47Sgongwei 	iscsi_service(lun->context, 0);
5571519aa47Sgongwei 	return SPDK_POLLER_BUSY;
5581519aa47Sgongwei }
5591519aa47Sgongwei 
5601519aa47Sgongwei static int
bdev_iscsi_no_main_ch_poll(void * arg)56157de009aSJim Harris bdev_iscsi_no_main_ch_poll(void *arg)
56207fe6a43SSeth Howell {
56307fe6a43SSeth Howell 	struct bdev_iscsi_lun *lun = arg;
564eb05cbd6SMaciej Szwed 	enum spdk_thread_poller_rc rc = SPDK_POLLER_IDLE;
56507fe6a43SSeth Howell 
56607fe6a43SSeth Howell 	if (pthread_mutex_trylock(&lun->mutex)) {
56707fe6a43SSeth Howell 		/* Don't care about the error code here. */
568eb05cbd6SMaciej Szwed 		return SPDK_POLLER_IDLE;
56907fe6a43SSeth Howell 	}
57007fe6a43SSeth Howell 
57107fe6a43SSeth Howell 	if (lun->ch_count == 0) {
57207fe6a43SSeth Howell 		rc = bdev_iscsi_poll_lun(arg);
57307fe6a43SSeth Howell 	}
57407fe6a43SSeth Howell 
57507fe6a43SSeth Howell 	pthread_mutex_unlock(&lun->mutex);
57607fe6a43SSeth Howell 	return rc;
57707fe6a43SSeth Howell }
57807fe6a43SSeth Howell 
57907fe6a43SSeth Howell static void
bdev_iscsi_get_buf_cb(struct spdk_io_channel * ch,struct spdk_bdev_io * bdev_io,bool success)58007fe6a43SSeth Howell bdev_iscsi_get_buf_cb(struct spdk_io_channel *ch, struct spdk_bdev_io *bdev_io,
58107fe6a43SSeth Howell 		      bool success)
58207fe6a43SSeth Howell {
58307fe6a43SSeth Howell 	if (!success) {
58407fe6a43SSeth Howell 		spdk_bdev_io_complete(bdev_io, SPDK_BDEV_IO_STATUS_FAILED);
58507fe6a43SSeth Howell 		return;
58607fe6a43SSeth Howell 	}
58707fe6a43SSeth Howell 
58807fe6a43SSeth Howell 	bdev_iscsi_readv((struct bdev_iscsi_lun *)bdev_io->bdev->ctxt,
58907fe6a43SSeth Howell 			 (struct bdev_iscsi_io *)bdev_io->driver_ctx,
59007fe6a43SSeth Howell 			 bdev_io->u.bdev.iovs,
59107fe6a43SSeth Howell 			 bdev_io->u.bdev.iovcnt,
59207fe6a43SSeth Howell 			 bdev_io->u.bdev.num_blocks * bdev_io->bdev->blocklen,
59307fe6a43SSeth Howell 			 bdev_io->u.bdev.offset_blocks);
59407fe6a43SSeth Howell }
59507fe6a43SSeth Howell 
5968dd1cd21SBen Walker static void
_bdev_iscsi_submit_request(void * _bdev_io)5978dd1cd21SBen Walker _bdev_iscsi_submit_request(void *_bdev_io)
59807fe6a43SSeth Howell {
59907fe6a43SSeth Howell 	struct spdk_bdev_io *bdev_io = _bdev_io;
60007fe6a43SSeth Howell 	struct bdev_iscsi_io *iscsi_io = (struct bdev_iscsi_io *)bdev_io->driver_ctx;
60107fe6a43SSeth Howell 	struct bdev_iscsi_lun *lun = (struct bdev_iscsi_lun *)bdev_io->bdev->ctxt;
60207fe6a43SSeth Howell 
60307fe6a43SSeth Howell 	switch (bdev_io->type) {
60407fe6a43SSeth Howell 	case SPDK_BDEV_IO_TYPE_READ:
60507fe6a43SSeth Howell 		spdk_bdev_io_get_buf(bdev_io, bdev_iscsi_get_buf_cb,
60607fe6a43SSeth Howell 				     bdev_io->u.bdev.num_blocks * bdev_io->bdev->blocklen);
60707fe6a43SSeth Howell 		break;
60807fe6a43SSeth Howell 
60907fe6a43SSeth Howell 	case SPDK_BDEV_IO_TYPE_WRITE:
61007fe6a43SSeth Howell 		bdev_iscsi_writev(lun, iscsi_io,
61107fe6a43SSeth Howell 				  bdev_io->u.bdev.iovs,
61207fe6a43SSeth Howell 				  bdev_io->u.bdev.iovcnt,
61307fe6a43SSeth Howell 				  bdev_io->u.bdev.num_blocks * bdev_io->bdev->blocklen,
61407fe6a43SSeth Howell 				  bdev_io->u.bdev.offset_blocks);
61507fe6a43SSeth Howell 		break;
61607fe6a43SSeth Howell 	case SPDK_BDEV_IO_TYPE_FLUSH:
61707fe6a43SSeth Howell 		bdev_iscsi_flush(lun, iscsi_io,
61807fe6a43SSeth Howell 				 bdev_io->u.bdev.num_blocks,
61907fe6a43SSeth Howell 				 ISCSI_IMMEDIATE_DATA_NO,
62007fe6a43SSeth Howell 				 bdev_io->u.bdev.offset_blocks);
62107fe6a43SSeth Howell 		break;
62207fe6a43SSeth Howell 	case SPDK_BDEV_IO_TYPE_RESET:
62307fe6a43SSeth Howell 		bdev_iscsi_reset(bdev_io);
62407fe6a43SSeth Howell 		break;
62507fe6a43SSeth Howell 	case SPDK_BDEV_IO_TYPE_UNMAP:
62607fe6a43SSeth Howell 		bdev_iscsi_unmap(lun, iscsi_io,
62707fe6a43SSeth Howell 				 bdev_io->u.bdev.offset_blocks,
62807fe6a43SSeth Howell 				 bdev_io->u.bdev.num_blocks);
62907fe6a43SSeth Howell 		break;
63007fe6a43SSeth Howell 	default:
63107fe6a43SSeth Howell 		bdev_iscsi_io_complete(iscsi_io, SPDK_BDEV_IO_STATUS_FAILED);
63207fe6a43SSeth Howell 		break;
63307fe6a43SSeth Howell 	}
63407fe6a43SSeth Howell }
63507fe6a43SSeth Howell 
6368dd1cd21SBen Walker static void
bdev_iscsi_submit_request(struct spdk_io_channel * _ch,struct spdk_bdev_io * bdev_io)6378dd1cd21SBen Walker bdev_iscsi_submit_request(struct spdk_io_channel *_ch, struct spdk_bdev_io *bdev_io)
63807fe6a43SSeth Howell {
63907fe6a43SSeth Howell 	struct spdk_thread *submit_td = spdk_io_channel_get_thread(_ch);
64007fe6a43SSeth Howell 	struct bdev_iscsi_io *iscsi_io = (struct bdev_iscsi_io *)bdev_io->driver_ctx;
64107fe6a43SSeth Howell 	struct bdev_iscsi_lun *lun = (struct bdev_iscsi_lun *)bdev_io->bdev->ctxt;
64207fe6a43SSeth Howell 
6436b7e9d0aSGangCao 	iscsi_io->lun = lun;
6446b7e9d0aSGangCao 
64557de009aSJim Harris 	if (lun->main_td != submit_td) {
64607fe6a43SSeth Howell 		iscsi_io->submit_td = submit_td;
64757de009aSJim Harris 		spdk_thread_send_msg(lun->main_td, _bdev_iscsi_submit_request, bdev_io);
64807fe6a43SSeth Howell 		return;
64907fe6a43SSeth Howell 	} else {
65007fe6a43SSeth Howell 		iscsi_io->submit_td = NULL;
65107fe6a43SSeth Howell 	}
65207fe6a43SSeth Howell 
65307fe6a43SSeth Howell 	_bdev_iscsi_submit_request(bdev_io);
65407fe6a43SSeth Howell }
65507fe6a43SSeth Howell 
65607fe6a43SSeth Howell static bool
bdev_iscsi_io_type_supported(void * ctx,enum spdk_bdev_io_type io_type)65707fe6a43SSeth Howell bdev_iscsi_io_type_supported(void *ctx, enum spdk_bdev_io_type io_type)
65807fe6a43SSeth Howell {
65907fe6a43SSeth Howell 	struct bdev_iscsi_lun *lun = ctx;
66007fe6a43SSeth Howell 
66107fe6a43SSeth Howell 	switch (io_type) {
66207fe6a43SSeth Howell 	case SPDK_BDEV_IO_TYPE_READ:
66307fe6a43SSeth Howell 	case SPDK_BDEV_IO_TYPE_WRITE:
66407fe6a43SSeth Howell 	case SPDK_BDEV_IO_TYPE_FLUSH:
66507fe6a43SSeth Howell 	case SPDK_BDEV_IO_TYPE_RESET:
66607fe6a43SSeth Howell 		return true;
66707fe6a43SSeth Howell 
66807fe6a43SSeth Howell 	case SPDK_BDEV_IO_TYPE_UNMAP:
66907fe6a43SSeth Howell 		return lun->unmap_supported;
67007fe6a43SSeth Howell 	default:
67107fe6a43SSeth Howell 		return false;
67207fe6a43SSeth Howell 	}
67307fe6a43SSeth Howell }
67407fe6a43SSeth Howell 
67507fe6a43SSeth Howell static int
bdev_iscsi_create_cb(void * io_device,void * ctx_buf)67607fe6a43SSeth Howell bdev_iscsi_create_cb(void *io_device, void *ctx_buf)
67707fe6a43SSeth Howell {
67807fe6a43SSeth Howell 	struct bdev_iscsi_io_channel *ch = ctx_buf;
67907fe6a43SSeth Howell 	struct bdev_iscsi_lun *lun = io_device;
68007fe6a43SSeth Howell 
68107fe6a43SSeth Howell 	pthread_mutex_lock(&lun->mutex);
68207fe6a43SSeth Howell 	if (lun->ch_count == 0) {
68357de009aSJim Harris 		assert(lun->main_td == NULL);
68457de009aSJim Harris 		lun->main_td = spdk_get_thread();
685ab0bc5c2SShuhei Matsumoto 		lun->poller = SPDK_POLLER_REGISTER(bdev_iscsi_poll_lun, lun, 0);
686c8e594c2Sgongwei 		if (g_opts.timeout_sec > 0) {
6871519aa47Sgongwei 			lun->timeout_poller = SPDK_POLLER_REGISTER(bdev_iscsi_poll_lun_timeout, lun,
6881519aa47Sgongwei 					      g_opts.timeout_poller_period_us);
6891519aa47Sgongwei 		}
69007fe6a43SSeth Howell 		ch->lun = lun;
69107fe6a43SSeth Howell 	}
69207fe6a43SSeth Howell 	lun->ch_count++;
69307fe6a43SSeth Howell 	pthread_mutex_unlock(&lun->mutex);
69407fe6a43SSeth Howell 
69507fe6a43SSeth Howell 	return 0;
69607fe6a43SSeth Howell }
69707fe6a43SSeth Howell 
69807fe6a43SSeth Howell static void
_iscsi_destroy_cb(void * ctx)69950529593SBen Walker _iscsi_destroy_cb(void *ctx)
70050529593SBen Walker {
70150529593SBen Walker 	struct bdev_iscsi_lun *lun = ctx;
70250529593SBen Walker 
70350529593SBen Walker 	pthread_mutex_lock(&lun->mutex);
70450529593SBen Walker 
70557de009aSJim Harris 	assert(lun->main_td == spdk_get_thread());
70650529593SBen Walker 	assert(lun->ch_count > 0);
70750529593SBen Walker 
70850529593SBen Walker 	lun->ch_count--;
70950529593SBen Walker 	if (lun->ch_count > 0) {
71050529593SBen Walker 		pthread_mutex_unlock(&lun->mutex);
71150529593SBen Walker 		return;
71250529593SBen Walker 	}
71350529593SBen Walker 
71457de009aSJim Harris 	lun->main_td = NULL;
71550529593SBen Walker 	spdk_poller_unregister(&lun->poller);
7161519aa47Sgongwei 	spdk_poller_unregister(&lun->timeout_poller);
71750529593SBen Walker 
71850529593SBen Walker 	pthread_mutex_unlock(&lun->mutex);
71950529593SBen Walker }
72050529593SBen Walker 
72150529593SBen Walker static void
bdev_iscsi_destroy_cb(void * io_device,void * ctx_buf)72207fe6a43SSeth Howell bdev_iscsi_destroy_cb(void *io_device, void *ctx_buf)
72307fe6a43SSeth Howell {
72407fe6a43SSeth Howell 	struct bdev_iscsi_lun *lun = io_device;
72550529593SBen Walker 	struct spdk_thread *thread;
72607fe6a43SSeth Howell 
72707fe6a43SSeth Howell 	pthread_mutex_lock(&lun->mutex);
72807fe6a43SSeth Howell 	lun->ch_count--;
72907fe6a43SSeth Howell 	if (lun->ch_count == 0) {
73057de009aSJim Harris 		assert(lun->main_td != NULL);
73107fe6a43SSeth Howell 
73257de009aSJim Harris 		if (lun->main_td != spdk_get_thread()) {
73350529593SBen Walker 			/* The final channel was destroyed on a different thread
73450529593SBen Walker 			 * than where the first channel was created. Pass a message
73557de009aSJim Harris 			 * to the main thread to unregister the poller. */
73650529593SBen Walker 			lun->ch_count++;
73757de009aSJim Harris 			thread = lun->main_td;
73850529593SBen Walker 			pthread_mutex_unlock(&lun->mutex);
73950529593SBen Walker 			spdk_thread_send_msg(thread, _iscsi_destroy_cb, lun);
74050529593SBen Walker 			return;
74150529593SBen Walker 		}
74250529593SBen Walker 
74357de009aSJim Harris 		lun->main_td = NULL;
74407fe6a43SSeth Howell 		spdk_poller_unregister(&lun->poller);
7451519aa47Sgongwei 		spdk_poller_unregister(&lun->timeout_poller);
74607fe6a43SSeth Howell 	}
74707fe6a43SSeth Howell 	pthread_mutex_unlock(&lun->mutex);
74807fe6a43SSeth Howell }
74907fe6a43SSeth Howell 
75007fe6a43SSeth Howell static struct spdk_io_channel *
bdev_iscsi_get_io_channel(void * ctx)75107fe6a43SSeth Howell bdev_iscsi_get_io_channel(void *ctx)
75207fe6a43SSeth Howell {
75307fe6a43SSeth Howell 	struct bdev_iscsi_lun *lun = ctx;
75407fe6a43SSeth Howell 
75507fe6a43SSeth Howell 	return spdk_get_io_channel(lun);
75607fe6a43SSeth Howell }
75707fe6a43SSeth Howell 
75807fe6a43SSeth Howell static int
bdev_iscsi_dump_info_json(void * ctx,struct spdk_json_write_ctx * w)75907fe6a43SSeth Howell bdev_iscsi_dump_info_json(void *ctx, struct spdk_json_write_ctx *w)
76007fe6a43SSeth Howell {
76107fe6a43SSeth Howell 	struct bdev_iscsi_lun *lun = ctx;
76207fe6a43SSeth Howell 
76307fe6a43SSeth Howell 	spdk_json_write_named_object_begin(w, "iscsi");
76407fe6a43SSeth Howell 	spdk_json_write_named_string(w, "initiator_name", lun->initiator_iqn);
76507fe6a43SSeth Howell 	spdk_json_write_named_string(w, "url", lun->url);
76607fe6a43SSeth Howell 	spdk_json_write_object_end(w);
76707fe6a43SSeth Howell 
76807fe6a43SSeth Howell 	return 0;
76907fe6a43SSeth Howell }
77007fe6a43SSeth Howell 
77107fe6a43SSeth Howell static void
bdev_iscsi_write_config_json(struct spdk_bdev * bdev,struct spdk_json_write_ctx * w)77207fe6a43SSeth Howell bdev_iscsi_write_config_json(struct spdk_bdev *bdev, struct spdk_json_write_ctx *w)
77307fe6a43SSeth Howell {
77407fe6a43SSeth Howell 	struct bdev_iscsi_lun *lun = bdev->ctxt;
77507fe6a43SSeth Howell 
77607fe6a43SSeth Howell 	pthread_mutex_lock(&lun->mutex);
77707fe6a43SSeth Howell 	spdk_json_write_object_begin(w);
77807fe6a43SSeth Howell 
7799f5cbf4cSMaciej Wawryk 	spdk_json_write_named_string(w, "method", "bdev_iscsi_create");
78007fe6a43SSeth Howell 
78107fe6a43SSeth Howell 	spdk_json_write_named_object_begin(w, "params");
78207fe6a43SSeth Howell 	spdk_json_write_named_string(w, "name", bdev->name);
78307fe6a43SSeth Howell 	spdk_json_write_named_string(w, "initiator_iqn", lun->initiator_iqn);
78407fe6a43SSeth Howell 	spdk_json_write_named_string(w, "url", lun->url);
78507fe6a43SSeth Howell 	spdk_json_write_object_end(w);
78607fe6a43SSeth Howell 
78707fe6a43SSeth Howell 	spdk_json_write_object_end(w);
78807fe6a43SSeth Howell 	pthread_mutex_unlock(&lun->mutex);
78907fe6a43SSeth Howell }
79007fe6a43SSeth Howell 
79107fe6a43SSeth Howell static const struct spdk_bdev_fn_table iscsi_fn_table = {
79207fe6a43SSeth Howell 	.destruct		= bdev_iscsi_destruct,
79307fe6a43SSeth Howell 	.submit_request		= bdev_iscsi_submit_request,
79407fe6a43SSeth Howell 	.io_type_supported	= bdev_iscsi_io_type_supported,
79507fe6a43SSeth Howell 	.get_io_channel		= bdev_iscsi_get_io_channel,
79607fe6a43SSeth Howell 	.dump_info_json		= bdev_iscsi_dump_info_json,
79707fe6a43SSeth Howell 	.write_config_json	= bdev_iscsi_write_config_json,
79807fe6a43SSeth Howell };
79907fe6a43SSeth Howell 
80007fe6a43SSeth Howell static int
create_iscsi_lun(struct bdev_iscsi_conn_req * req,uint64_t num_blocks,uint32_t block_size,struct spdk_bdev ** bdev,uint8_t lbppbe)801938cc7d9SChangpeng Liu create_iscsi_lun(struct bdev_iscsi_conn_req *req, uint64_t num_blocks,
802938cc7d9SChangpeng Liu 		 uint32_t block_size, struct spdk_bdev **bdev, uint8_t lbppbe)
80307fe6a43SSeth Howell {
80407fe6a43SSeth Howell 	struct bdev_iscsi_lun *lun;
80507fe6a43SSeth Howell 	int rc;
80607fe6a43SSeth Howell 
807*746549cfSCody Cheng 	lun = calloc(1, sizeof(*lun));
80807fe6a43SSeth Howell 	if (!lun) {
80907fe6a43SSeth Howell 		SPDK_ERRLOG("Unable to allocate enough memory for iscsi backend\n");
81007fe6a43SSeth Howell 		return -ENOMEM;
81107fe6a43SSeth Howell 	}
81207fe6a43SSeth Howell 
813938cc7d9SChangpeng Liu 	lun->context = req->context;
814938cc7d9SChangpeng Liu 	lun->lun_id = req->lun;
815938cc7d9SChangpeng Liu 	lun->url = req->url;
816938cc7d9SChangpeng Liu 	lun->initiator_iqn = req->initiator_iqn;
81707fe6a43SSeth Howell 
81807fe6a43SSeth Howell 	pthread_mutex_init(&lun->mutex, NULL);
81907fe6a43SSeth Howell 
820938cc7d9SChangpeng Liu 	lun->bdev.name = req->bdev_name;
82107fe6a43SSeth Howell 	lun->bdev.product_name = "iSCSI LUN";
82207fe6a43SSeth Howell 	lun->bdev.module = &g_iscsi_bdev_module;
82307fe6a43SSeth Howell 	lun->bdev.blocklen = block_size;
8246cebe9d0SSwapnil Ingle 	lun->bdev.phys_blocklen = block_size * (1 << lbppbe);
82507fe6a43SSeth Howell 	lun->bdev.blockcnt = num_blocks;
82607fe6a43SSeth Howell 	lun->bdev.ctxt = lun;
827938cc7d9SChangpeng Liu 	lun->unmap_supported = req->unmap_supported;
828b885e23bSChangpeng Liu 	if (lun->unmap_supported) {
829b885e23bSChangpeng Liu 		lun->max_unmap = req->max_unmap;
830b885e23bSChangpeng Liu 		lun->bdev.max_unmap = req->max_unmap;
831b885e23bSChangpeng Liu 		lun->bdev.max_unmap_segments = BDEV_ISCSI_MAX_UNMAP_BLOCK_DESCS_COUNT;
832b885e23bSChangpeng Liu 	}
83307fe6a43SSeth Howell 
83407fe6a43SSeth Howell 	lun->bdev.fn_table = &iscsi_fn_table;
83507fe6a43SSeth Howell 
83607fe6a43SSeth Howell 	spdk_io_device_register(lun, bdev_iscsi_create_cb, bdev_iscsi_destroy_cb,
83707fe6a43SSeth Howell 				sizeof(struct bdev_iscsi_io_channel),
838938cc7d9SChangpeng Liu 				req->bdev_name);
83907fe6a43SSeth Howell 	rc = spdk_bdev_register(&lun->bdev);
84007fe6a43SSeth Howell 	if (rc) {
84107fe6a43SSeth Howell 		spdk_io_device_unregister(lun, NULL);
84207fe6a43SSeth Howell 		pthread_mutex_destroy(&lun->mutex);
84307fe6a43SSeth Howell 		free(lun);
84407fe6a43SSeth Howell 		return rc;
84507fe6a43SSeth Howell 	}
84607fe6a43SSeth Howell 
84757de009aSJim Harris 	lun->no_main_ch_poller_td = spdk_get_thread();
84857de009aSJim Harris 	lun->no_main_ch_poller = SPDK_POLLER_REGISTER(bdev_iscsi_no_main_ch_poll, lun,
84957de009aSJim Harris 				 BDEV_ISCSI_NO_MAIN_CH_POLL_US);
85007fe6a43SSeth Howell 
85107fe6a43SSeth Howell 	*bdev = &lun->bdev;
85207fe6a43SSeth Howell 	return 0;
85307fe6a43SSeth Howell }
85407fe6a43SSeth Howell 
85507fe6a43SSeth Howell static void
iscsi_readcapacity16_cb(struct iscsi_context * iscsi,int status,void * command_data,void * private_data)85607fe6a43SSeth Howell iscsi_readcapacity16_cb(struct iscsi_context *iscsi, int status,
85707fe6a43SSeth Howell 			void *command_data, void *private_data)
85807fe6a43SSeth Howell {
85907fe6a43SSeth Howell 	struct bdev_iscsi_conn_req *req = private_data;
86007fe6a43SSeth Howell 	struct scsi_readcapacity16 *readcap16;
86107fe6a43SSeth Howell 	struct spdk_bdev *bdev = NULL;
86207fe6a43SSeth Howell 	struct scsi_task *task = command_data;
8636b7e9d0aSGangCao 	struct scsi_task *retry_task = NULL;
86407fe6a43SSeth Howell 
86507fe6a43SSeth Howell 	if (status != SPDK_SCSI_STATUS_GOOD) {
86607fe6a43SSeth Howell 		SPDK_ERRLOG("iSCSI error: %s\n", iscsi_get_error(iscsi));
8676b7e9d0aSGangCao 		if (_bdev_iscsi_is_size_change(status, task)) {
8686b7e9d0aSGangCao 			scsi_free_scsi_task(task);
8696b7e9d0aSGangCao 			retry_task = iscsi_readcapacity16_task(iscsi, req->lun,
8706b7e9d0aSGangCao 							       iscsi_readcapacity16_cb, req);
8716b7e9d0aSGangCao 			if (retry_task) {
8726b7e9d0aSGangCao 				return;
8736b7e9d0aSGangCao 			}
8746b7e9d0aSGangCao 		}
87507fe6a43SSeth Howell 		goto ret;
87607fe6a43SSeth Howell 	}
87707fe6a43SSeth Howell 
87807fe6a43SSeth Howell 	readcap16 = scsi_datain_unmarshall(task);
87907fe6a43SSeth Howell 	if (!readcap16) {
88007fe6a43SSeth Howell 		status = -ENOMEM;
88107fe6a43SSeth Howell 		goto ret;
88207fe6a43SSeth Howell 	}
88307fe6a43SSeth Howell 
884938cc7d9SChangpeng Liu 	status = create_iscsi_lun(req, readcap16->returned_lba + 1, readcap16->block_length, &bdev,
8856cebe9d0SSwapnil Ingle 				  readcap16->lbppbe);
88607fe6a43SSeth Howell 	if (status) {
88707fe6a43SSeth Howell 		SPDK_ERRLOG("Unable to create iscsi bdev: %s (%d)\n", spdk_strerror(-status), status);
88807fe6a43SSeth Howell 	}
88907fe6a43SSeth Howell 
89007fe6a43SSeth Howell ret:
89107fe6a43SSeth Howell 	scsi_free_scsi_task(task);
89207fe6a43SSeth Howell 	complete_conn_req(req, bdev, status);
89307fe6a43SSeth Howell }
89407fe6a43SSeth Howell 
89507fe6a43SSeth Howell static void
bdev_iscsi_inquiry_bl_cb(struct iscsi_context * context,int status,void * _task,void * private_data)8962594e757SChangpeng Liu bdev_iscsi_inquiry_bl_cb(struct iscsi_context *context, int status, void *_task, void *private_data)
8972594e757SChangpeng Liu {
8982594e757SChangpeng Liu 	struct scsi_task *task = _task;
8992594e757SChangpeng Liu 	struct scsi_inquiry_block_limits *bl_inq = NULL;
9002594e757SChangpeng Liu 	struct bdev_iscsi_conn_req *req = private_data;
9012594e757SChangpeng Liu 
9022594e757SChangpeng Liu 	if (status == SPDK_SCSI_STATUS_GOOD) {
9032594e757SChangpeng Liu 		bl_inq = scsi_datain_unmarshall(task);
9042594e757SChangpeng Liu 		if (bl_inq != NULL) {
9052594e757SChangpeng Liu 			if (!bl_inq->max_unmap) {
9062594e757SChangpeng Liu 				SPDK_ERRLOG("Invalid max_unmap, use the default\n");
9072594e757SChangpeng Liu 				req->max_unmap = BDEV_ISCSI_DEFAULT_MAX_UNMAP_LBA_COUNT;
9082594e757SChangpeng Liu 			} else {
9092594e757SChangpeng Liu 				req->max_unmap = bl_inq->max_unmap;
9102594e757SChangpeng Liu 			}
9112594e757SChangpeng Liu 		}
9122594e757SChangpeng Liu 	}
9132594e757SChangpeng Liu 
9142594e757SChangpeng Liu 	scsi_free_scsi_task(task);
9152594e757SChangpeng Liu 	task = iscsi_readcapacity16_task(context, req->lun, iscsi_readcapacity16_cb, req);
9162594e757SChangpeng Liu 	if (task) {
9172594e757SChangpeng Liu 		return;
9182594e757SChangpeng Liu 	}
9192594e757SChangpeng Liu 
9202594e757SChangpeng Liu 	SPDK_ERRLOG("iSCSI error: %s\n", iscsi_get_error(req->context));
9212594e757SChangpeng Liu 	complete_conn_req(req, NULL, status);
9222594e757SChangpeng Liu }
9232594e757SChangpeng Liu 
9242594e757SChangpeng Liu static void
bdev_iscsi_inquiry_lbp_cb(struct iscsi_context * context,int status,void * _task,void * private_data)9252594e757SChangpeng Liu bdev_iscsi_inquiry_lbp_cb(struct iscsi_context *context, int status, void *_task,
9262594e757SChangpeng Liu 			  void *private_data)
92707fe6a43SSeth Howell {
92807fe6a43SSeth Howell 	struct scsi_task *task = _task;
92907fe6a43SSeth Howell 	struct scsi_inquiry_logical_block_provisioning *lbp_inq = NULL;
93007fe6a43SSeth Howell 	struct bdev_iscsi_conn_req *req = private_data;
93107fe6a43SSeth Howell 
93207fe6a43SSeth Howell 	if (status == SPDK_SCSI_STATUS_GOOD) {
93307fe6a43SSeth Howell 		lbp_inq = scsi_datain_unmarshall(task);
93407fe6a43SSeth Howell 		if (lbp_inq != NULL && lbp_inq->lbpu) {
93507fe6a43SSeth Howell 			req->unmap_supported = true;
9362594e757SChangpeng Liu 			scsi_free_scsi_task(task);
9372594e757SChangpeng Liu 
9382594e757SChangpeng Liu 			task = iscsi_inquiry_task(context, req->lun, 1,
9392594e757SChangpeng Liu 						  SCSI_INQUIRY_PAGECODE_BLOCK_LIMITS,
9402594e757SChangpeng Liu 						  255, bdev_iscsi_inquiry_bl_cb, req);
9412594e757SChangpeng Liu 			if (task) {
9422594e757SChangpeng Liu 				return;
94307fe6a43SSeth Howell 			}
94407fe6a43SSeth Howell 		}
9452594e757SChangpeng Liu 	} else {
9462594e757SChangpeng Liu 		scsi_free_scsi_task(task);
9472594e757SChangpeng Liu 	}
94807fe6a43SSeth Howell 
94907fe6a43SSeth Howell 	task = iscsi_readcapacity16_task(context, req->lun, iscsi_readcapacity16_cb, req);
95007fe6a43SSeth Howell 	if (task) {
95107fe6a43SSeth Howell 		return;
95207fe6a43SSeth Howell 	}
95307fe6a43SSeth Howell 
95407fe6a43SSeth Howell 	SPDK_ERRLOG("iSCSI error: %s\n", iscsi_get_error(req->context));
95507fe6a43SSeth Howell 	complete_conn_req(req, NULL, status);
95607fe6a43SSeth Howell }
95707fe6a43SSeth Howell 
95807fe6a43SSeth Howell static void
iscsi_connect_cb(struct iscsi_context * iscsi,int status,void * command_data,void * private_data)95907fe6a43SSeth Howell iscsi_connect_cb(struct iscsi_context *iscsi, int status,
96007fe6a43SSeth Howell 		 void *command_data, void *private_data)
96107fe6a43SSeth Howell {
96207fe6a43SSeth Howell 	struct bdev_iscsi_conn_req *req = private_data;
96307fe6a43SSeth Howell 	struct scsi_task *task;
96407fe6a43SSeth Howell 
96507fe6a43SSeth Howell 	if (status != SPDK_SCSI_STATUS_GOOD) {
96607fe6a43SSeth Howell 		goto ret;
96707fe6a43SSeth Howell 	}
96807fe6a43SSeth Howell 
96907fe6a43SSeth Howell 	task = iscsi_inquiry_task(iscsi, req->lun, 1,
97007fe6a43SSeth Howell 				  SCSI_INQUIRY_PAGECODE_LOGICAL_BLOCK_PROVISIONING,
9712594e757SChangpeng Liu 				  255, bdev_iscsi_inquiry_lbp_cb, req);
97207fe6a43SSeth Howell 	if (task) {
97307fe6a43SSeth Howell 		return;
97407fe6a43SSeth Howell 	}
97507fe6a43SSeth Howell 
97607fe6a43SSeth Howell ret:
97707fe6a43SSeth Howell 	SPDK_ERRLOG("iSCSI error: %s\n", iscsi_get_error(req->context));
97807fe6a43SSeth Howell 	complete_conn_req(req, NULL, status);
97907fe6a43SSeth Howell }
98007fe6a43SSeth Howell 
98107fe6a43SSeth Howell static int
iscsi_bdev_conn_poll(void * arg)98207fe6a43SSeth Howell iscsi_bdev_conn_poll(void *arg)
98307fe6a43SSeth Howell {
98407fe6a43SSeth Howell 	struct bdev_iscsi_conn_req *req, *tmp;
98507fe6a43SSeth Howell 	struct pollfd pfd;
98607fe6a43SSeth Howell 	struct iscsi_context *context;
98707fe6a43SSeth Howell 
988eb05cbd6SMaciej Szwed 	if (TAILQ_EMPTY(&g_iscsi_conn_req)) {
98967519098SJohn Levon 		spdk_poller_unregister(&g_conn_poller);
990eb05cbd6SMaciej Szwed 		return SPDK_POLLER_IDLE;
991eb05cbd6SMaciej Szwed 	}
992eb05cbd6SMaciej Szwed 
99307fe6a43SSeth Howell 	TAILQ_FOREACH_SAFE(req, &g_iscsi_conn_req, link, tmp) {
99407fe6a43SSeth Howell 		context = req->context;
99507fe6a43SSeth Howell 		pfd.fd = iscsi_get_fd(context);
99607fe6a43SSeth Howell 		pfd.events = iscsi_which_events(context);
99707fe6a43SSeth Howell 		pfd.revents = 0;
99807fe6a43SSeth Howell 		if (poll(&pfd, 1, 0) < 0) {
99907fe6a43SSeth Howell 			SPDK_ERRLOG("poll failed\n");
1000eb05cbd6SMaciej Szwed 			return SPDK_POLLER_BUSY;
100107fe6a43SSeth Howell 		}
100207fe6a43SSeth Howell 
100307fe6a43SSeth Howell 		if (pfd.revents != 0) {
100407fe6a43SSeth Howell 			if (iscsi_service(context, pfd.revents) < 0) {
100507fe6a43SSeth Howell 				SPDK_ERRLOG("iscsi_service failed: %s\n", iscsi_get_error(context));
100607fe6a43SSeth Howell 			}
100707fe6a43SSeth Howell 		}
100807fe6a43SSeth Howell 
1009f76cf582SBen Walker 		if (req->status == 0) {
1010f76cf582SBen Walker 			/*
1011f76cf582SBen Walker 			 * The request completed successfully.
1012f76cf582SBen Walker 			 */
1013f76cf582SBen Walker 			free(req);
1014f76cf582SBen Walker 		} else if (req->status > 0) {
101507fe6a43SSeth Howell 			/*
101607fe6a43SSeth Howell 			 * An error has occurred during connecting.  This req has already
101707fe6a43SSeth Howell 			 * been removed from the g_iscsi_conn_req list, but we needed to
101807fe6a43SSeth Howell 			 * wait until iscsi_service unwound before we could free the req.
101907fe6a43SSeth Howell 			 */
102007fe6a43SSeth Howell 			_bdev_iscsi_conn_req_free(req);
102107fe6a43SSeth Howell 		}
102207fe6a43SSeth Howell 	}
1023eb05cbd6SMaciej Szwed 	return SPDK_POLLER_BUSY;
102407fe6a43SSeth Howell }
102507fe6a43SSeth Howell 
102607fe6a43SSeth Howell int
create_iscsi_disk(const char * bdev_name,const char * url,const char * initiator_iqn,spdk_bdev_iscsi_create_cb cb_fn,void * cb_arg)102707fe6a43SSeth Howell create_iscsi_disk(const char *bdev_name, const char *url, const char *initiator_iqn,
102807fe6a43SSeth Howell 		  spdk_bdev_iscsi_create_cb cb_fn, void *cb_arg)
102907fe6a43SSeth Howell {
103007fe6a43SSeth Howell 	struct bdev_iscsi_conn_req *req;
103107fe6a43SSeth Howell 	struct iscsi_url *iscsi_url = NULL;
103207fe6a43SSeth Howell 	int rc;
103307fe6a43SSeth Howell 
103407fe6a43SSeth Howell 	if (!bdev_name || !url || !initiator_iqn || strlen(initiator_iqn) == 0 || !cb_fn) {
103507fe6a43SSeth Howell 		return -EINVAL;
103607fe6a43SSeth Howell 	}
103707fe6a43SSeth Howell 
103807fe6a43SSeth Howell 	req = calloc(1, sizeof(struct bdev_iscsi_conn_req));
103907fe6a43SSeth Howell 	if (!req) {
104007fe6a43SSeth Howell 		SPDK_ERRLOG("Cannot allocate pointer of struct bdev_iscsi_conn_req\n");
104107fe6a43SSeth Howell 		return -ENOMEM;
104207fe6a43SSeth Howell 	}
104307fe6a43SSeth Howell 
104407fe6a43SSeth Howell 	req->status = SCSI_STATUS_GOOD;
104507fe6a43SSeth Howell 	req->bdev_name = strdup(bdev_name);
104607fe6a43SSeth Howell 	req->url = strdup(url);
104707fe6a43SSeth Howell 	req->initiator_iqn = strdup(initiator_iqn);
104807fe6a43SSeth Howell 	req->context = iscsi_create_context(initiator_iqn);
104907fe6a43SSeth Howell 	if (!req->bdev_name || !req->url || !req->initiator_iqn || !req->context) {
105007fe6a43SSeth Howell 		SPDK_ERRLOG("Out of memory\n");
105107fe6a43SSeth Howell 		rc = -ENOMEM;
105207fe6a43SSeth Howell 		goto err;
105307fe6a43SSeth Howell 	}
105407fe6a43SSeth Howell 
105507fe6a43SSeth Howell 	req->create_cb = cb_fn;
105607fe6a43SSeth Howell 	req->create_cb_arg = cb_arg;
105707fe6a43SSeth Howell 
105807fe6a43SSeth Howell 	iscsi_url = iscsi_parse_full_url(req->context, url);
105907fe6a43SSeth Howell 	if (iscsi_url == NULL) {
106007fe6a43SSeth Howell 		SPDK_ERRLOG("could not parse URL: %s\n", iscsi_get_error(req->context));
106107fe6a43SSeth Howell 		rc = -EINVAL;
106207fe6a43SSeth Howell 		goto err;
106307fe6a43SSeth Howell 	}
106407fe6a43SSeth Howell 
106507fe6a43SSeth Howell 	req->lun = iscsi_url->lun;
106607fe6a43SSeth Howell 	rc = iscsi_set_session_type(req->context, ISCSI_SESSION_NORMAL);
106707fe6a43SSeth Howell 	rc = rc ? rc : iscsi_set_header_digest(req->context, ISCSI_HEADER_DIGEST_NONE);
106807fe6a43SSeth Howell 	rc = rc ? rc : iscsi_set_targetname(req->context, iscsi_url->target);
1069c8e594c2Sgongwei 	rc = rc ? rc : iscsi_set_timeout(req->context, g_opts.timeout_sec);
107007fe6a43SSeth Howell 	rc = rc ? rc : iscsi_full_connect_async(req->context, iscsi_url->portal, iscsi_url->lun,
107107fe6a43SSeth Howell 						iscsi_connect_cb, req);
107207fe6a43SSeth Howell 	if (rc == 0 && iscsi_url->user[0] != '\0') {
107307fe6a43SSeth Howell 		rc = iscsi_set_initiator_username_pwd(req->context, iscsi_url->user, iscsi_url->passwd);
107407fe6a43SSeth Howell 	}
107507fe6a43SSeth Howell 
107607fe6a43SSeth Howell 	if (rc < 0) {
107707fe6a43SSeth Howell 		SPDK_ERRLOG("Failed to connect provided URL=%s: %s\n", url, iscsi_get_error(req->context));
107807fe6a43SSeth Howell 		goto err;
107907fe6a43SSeth Howell 	}
108007fe6a43SSeth Howell 
108107fe6a43SSeth Howell 	iscsi_destroy_url(iscsi_url);
1082f76cf582SBen Walker 	req->status = -1;
108307fe6a43SSeth Howell 	TAILQ_INSERT_TAIL(&g_iscsi_conn_req, req, link);
108407fe6a43SSeth Howell 	if (!g_conn_poller) {
1085ab0bc5c2SShuhei Matsumoto 		g_conn_poller = SPDK_POLLER_REGISTER(iscsi_bdev_conn_poll, NULL, BDEV_ISCSI_CONNECTION_POLL_US);
108607fe6a43SSeth Howell 	}
108707fe6a43SSeth Howell 
108807fe6a43SSeth Howell 	return 0;
108907fe6a43SSeth Howell 
109007fe6a43SSeth Howell err:
109107fe6a43SSeth Howell 	/* iscsi_destroy_url() is not NULL-proof */
109207fe6a43SSeth Howell 	if (iscsi_url) {
109307fe6a43SSeth Howell 		iscsi_destroy_url(iscsi_url);
109407fe6a43SSeth Howell 	}
109507fe6a43SSeth Howell 
109607fe6a43SSeth Howell 	if (req->context) {
109707fe6a43SSeth Howell 		iscsi_destroy_context(req->context);
109807fe6a43SSeth Howell 	}
109907fe6a43SSeth Howell 
110007fe6a43SSeth Howell 	free(req->initiator_iqn);
110107fe6a43SSeth Howell 	free(req->bdev_name);
110207fe6a43SSeth Howell 	free(req->url);
110307fe6a43SSeth Howell 	free(req);
110407fe6a43SSeth Howell 	return rc;
110507fe6a43SSeth Howell }
110607fe6a43SSeth Howell 
110707fe6a43SSeth Howell void
delete_iscsi_disk(const char * bdev_name,spdk_delete_iscsi_complete cb_fn,void * cb_arg)11084573e4ccSShuhei Matsumoto delete_iscsi_disk(const char *bdev_name, spdk_delete_iscsi_complete cb_fn, void *cb_arg)
110907fe6a43SSeth Howell {
11104573e4ccSShuhei Matsumoto 	int rc;
111107fe6a43SSeth Howell 
11124573e4ccSShuhei Matsumoto 	rc = spdk_bdev_unregister_by_name(bdev_name, &g_iscsi_bdev_module, cb_fn, cb_arg);
11134573e4ccSShuhei Matsumoto 	if (rc != 0) {
11144573e4ccSShuhei Matsumoto 		cb_fn(cb_arg, rc);
11154573e4ccSShuhei Matsumoto 	}
111607fe6a43SSeth Howell }
111707fe6a43SSeth Howell 
111807fe6a43SSeth Howell static int
bdev_iscsi_initialize(void)111907fe6a43SSeth Howell bdev_iscsi_initialize(void)
112007fe6a43SSeth Howell {
112107fe6a43SSeth Howell 	return 0;
112207fe6a43SSeth Howell }
112307fe6a43SSeth Howell 
11242172c432STomasz Zawadzki SPDK_LOG_REGISTER_COMPONENT(iscsi_init)
1125