162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * Copyright (C) 2021 Broadcom. All Rights Reserved. The term
462306a36Sopenharmony_ci * “Broadcom” refers to Broadcom Inc. and/or its subsidiaries.
562306a36Sopenharmony_ci */
662306a36Sopenharmony_ci
762306a36Sopenharmony_ci#include <target/target_core_base.h>
862306a36Sopenharmony_ci#include <target/target_core_fabric.h>
962306a36Sopenharmony_ci#include "efct_driver.h"
1062306a36Sopenharmony_ci#include "efct_lio.h"
1162306a36Sopenharmony_ci
1262306a36Sopenharmony_ci/*
1362306a36Sopenharmony_ci * lio_wq is used to call the LIO backed during creation or deletion of
1462306a36Sopenharmony_ci * sessions. This brings serialization to the session management as we create
1562306a36Sopenharmony_ci * single threaded work queue.
1662306a36Sopenharmony_ci */
1762306a36Sopenharmony_cistatic struct workqueue_struct *lio_wq;
1862306a36Sopenharmony_ci
1962306a36Sopenharmony_cistatic int
2062306a36Sopenharmony_ciefct_format_wwn(char *str, size_t len, const char *pre, u64 wwn)
2162306a36Sopenharmony_ci{
2262306a36Sopenharmony_ci	u8 a[8];
2362306a36Sopenharmony_ci
2462306a36Sopenharmony_ci	put_unaligned_be64(wwn, a);
2562306a36Sopenharmony_ci	return snprintf(str, len, "%s%8phC", pre, a);
2662306a36Sopenharmony_ci}
2762306a36Sopenharmony_ci
2862306a36Sopenharmony_cistatic int
2962306a36Sopenharmony_ciefct_lio_parse_wwn(const char *name, u64 *wwp, u8 npiv)
3062306a36Sopenharmony_ci{
3162306a36Sopenharmony_ci	int num;
3262306a36Sopenharmony_ci	u8 b[8];
3362306a36Sopenharmony_ci
3462306a36Sopenharmony_ci	if (npiv) {
3562306a36Sopenharmony_ci		num = sscanf(name,
3662306a36Sopenharmony_ci			     "%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx",
3762306a36Sopenharmony_ci			     &b[0], &b[1], &b[2], &b[3], &b[4], &b[5], &b[6],
3862306a36Sopenharmony_ci			     &b[7]);
3962306a36Sopenharmony_ci	} else {
4062306a36Sopenharmony_ci		num = sscanf(name,
4162306a36Sopenharmony_ci		      "%02hhx:%02hhx:%02hhx:%02hhx:%02hhx:%02hhx:%02hhx:%02hhx",
4262306a36Sopenharmony_ci			     &b[0], &b[1], &b[2], &b[3], &b[4], &b[5], &b[6],
4362306a36Sopenharmony_ci			     &b[7]);
4462306a36Sopenharmony_ci	}
4562306a36Sopenharmony_ci
4662306a36Sopenharmony_ci	if (num != 8)
4762306a36Sopenharmony_ci		return -EINVAL;
4862306a36Sopenharmony_ci
4962306a36Sopenharmony_ci	*wwp = get_unaligned_be64(b);
5062306a36Sopenharmony_ci	return 0;
5162306a36Sopenharmony_ci}
5262306a36Sopenharmony_ci
5362306a36Sopenharmony_cistatic int
5462306a36Sopenharmony_ciefct_lio_parse_npiv_wwn(const char *name, size_t size, u64 *wwpn, u64 *wwnn)
5562306a36Sopenharmony_ci{
5662306a36Sopenharmony_ci	unsigned int cnt = size;
5762306a36Sopenharmony_ci	int rc;
5862306a36Sopenharmony_ci
5962306a36Sopenharmony_ci	*wwpn = *wwnn = 0;
6062306a36Sopenharmony_ci	if (name[cnt - 1] == '\n' || name[cnt - 1] == 0)
6162306a36Sopenharmony_ci		cnt--;
6262306a36Sopenharmony_ci
6362306a36Sopenharmony_ci	/* validate we have enough characters for WWPN */
6462306a36Sopenharmony_ci	if ((cnt != (16 + 1 + 16)) || (name[16] != ':'))
6562306a36Sopenharmony_ci		return -EINVAL;
6662306a36Sopenharmony_ci
6762306a36Sopenharmony_ci	rc = efct_lio_parse_wwn(&name[0], wwpn, 1);
6862306a36Sopenharmony_ci	if (rc)
6962306a36Sopenharmony_ci		return rc;
7062306a36Sopenharmony_ci
7162306a36Sopenharmony_ci	rc = efct_lio_parse_wwn(&name[17], wwnn, 1);
7262306a36Sopenharmony_ci	if (rc)
7362306a36Sopenharmony_ci		return rc;
7462306a36Sopenharmony_ci
7562306a36Sopenharmony_ci	return 0;
7662306a36Sopenharmony_ci}
7762306a36Sopenharmony_ci
7862306a36Sopenharmony_cistatic ssize_t
7962306a36Sopenharmony_ciefct_lio_tpg_enable_show(struct config_item *item, char *page)
8062306a36Sopenharmony_ci{
8162306a36Sopenharmony_ci	struct se_portal_group *se_tpg = to_tpg(item);
8262306a36Sopenharmony_ci	struct efct_lio_tpg *tpg =
8362306a36Sopenharmony_ci		container_of(se_tpg, struct efct_lio_tpg, tpg);
8462306a36Sopenharmony_ci
8562306a36Sopenharmony_ci	return snprintf(page, PAGE_SIZE, "%d\n", tpg->enabled);
8662306a36Sopenharmony_ci}
8762306a36Sopenharmony_ci
8862306a36Sopenharmony_cistatic ssize_t
8962306a36Sopenharmony_ciefct_lio_tpg_enable_store(struct config_item *item, const char *page,
9062306a36Sopenharmony_ci			  size_t count)
9162306a36Sopenharmony_ci{
9262306a36Sopenharmony_ci	struct se_portal_group *se_tpg = to_tpg(item);
9362306a36Sopenharmony_ci	struct efct_lio_tpg *tpg =
9462306a36Sopenharmony_ci		container_of(se_tpg, struct efct_lio_tpg, tpg);
9562306a36Sopenharmony_ci	struct efct *efct;
9662306a36Sopenharmony_ci	struct efc *efc;
9762306a36Sopenharmony_ci	unsigned long op;
9862306a36Sopenharmony_ci
9962306a36Sopenharmony_ci	if (!tpg->nport || !tpg->nport->efct) {
10062306a36Sopenharmony_ci		pr_err("%s: Unable to find EFCT device\n", __func__);
10162306a36Sopenharmony_ci		return -EINVAL;
10262306a36Sopenharmony_ci	}
10362306a36Sopenharmony_ci
10462306a36Sopenharmony_ci	efct = tpg->nport->efct;
10562306a36Sopenharmony_ci	efc = efct->efcport;
10662306a36Sopenharmony_ci
10762306a36Sopenharmony_ci	if (kstrtoul(page, 0, &op) < 0)
10862306a36Sopenharmony_ci		return -EINVAL;
10962306a36Sopenharmony_ci
11062306a36Sopenharmony_ci	if (op == 1) {
11162306a36Sopenharmony_ci		int ret;
11262306a36Sopenharmony_ci
11362306a36Sopenharmony_ci		tpg->enabled = true;
11462306a36Sopenharmony_ci		efc_log_debug(efct, "enable portal group %d\n", tpg->tpgt);
11562306a36Sopenharmony_ci
11662306a36Sopenharmony_ci		ret = efct_xport_control(efct->xport, EFCT_XPORT_PORT_ONLINE);
11762306a36Sopenharmony_ci		if (ret) {
11862306a36Sopenharmony_ci			efct->tgt_efct.lio_nport = NULL;
11962306a36Sopenharmony_ci			efc_log_debug(efct, "cannot bring port online\n");
12062306a36Sopenharmony_ci			return ret;
12162306a36Sopenharmony_ci		}
12262306a36Sopenharmony_ci	} else if (op == 0) {
12362306a36Sopenharmony_ci		efc_log_debug(efct, "disable portal group %d\n", tpg->tpgt);
12462306a36Sopenharmony_ci
12562306a36Sopenharmony_ci		if (efc->domain && efc->domain->nport)
12662306a36Sopenharmony_ci			efct_scsi_tgt_del_nport(efc, efc->domain->nport);
12762306a36Sopenharmony_ci
12862306a36Sopenharmony_ci		tpg->enabled = false;
12962306a36Sopenharmony_ci	} else {
13062306a36Sopenharmony_ci		return -EINVAL;
13162306a36Sopenharmony_ci	}
13262306a36Sopenharmony_ci
13362306a36Sopenharmony_ci	return count;
13462306a36Sopenharmony_ci}
13562306a36Sopenharmony_ci
13662306a36Sopenharmony_cistatic ssize_t
13762306a36Sopenharmony_ciefct_lio_npiv_tpg_enable_show(struct config_item *item, char *page)
13862306a36Sopenharmony_ci{
13962306a36Sopenharmony_ci	struct se_portal_group *se_tpg = to_tpg(item);
14062306a36Sopenharmony_ci	struct efct_lio_tpg *tpg =
14162306a36Sopenharmony_ci		container_of(se_tpg, struct efct_lio_tpg, tpg);
14262306a36Sopenharmony_ci
14362306a36Sopenharmony_ci	return snprintf(page, PAGE_SIZE, "%d\n", tpg->enabled);
14462306a36Sopenharmony_ci}
14562306a36Sopenharmony_ci
14662306a36Sopenharmony_cistatic ssize_t
14762306a36Sopenharmony_ciefct_lio_npiv_tpg_enable_store(struct config_item *item, const char *page,
14862306a36Sopenharmony_ci			       size_t count)
14962306a36Sopenharmony_ci{
15062306a36Sopenharmony_ci	struct se_portal_group *se_tpg = to_tpg(item);
15162306a36Sopenharmony_ci	struct efct_lio_tpg *tpg =
15262306a36Sopenharmony_ci		container_of(se_tpg, struct efct_lio_tpg, tpg);
15362306a36Sopenharmony_ci	struct efct_lio_vport *lio_vport = tpg->vport;
15462306a36Sopenharmony_ci	struct efct *efct;
15562306a36Sopenharmony_ci	struct efc *efc;
15662306a36Sopenharmony_ci	unsigned long op;
15762306a36Sopenharmony_ci
15862306a36Sopenharmony_ci	if (kstrtoul(page, 0, &op) < 0)
15962306a36Sopenharmony_ci		return -EINVAL;
16062306a36Sopenharmony_ci
16162306a36Sopenharmony_ci	if (!lio_vport) {
16262306a36Sopenharmony_ci		pr_err("Unable to find vport\n");
16362306a36Sopenharmony_ci		return -EINVAL;
16462306a36Sopenharmony_ci	}
16562306a36Sopenharmony_ci
16662306a36Sopenharmony_ci	efct = lio_vport->efct;
16762306a36Sopenharmony_ci	efc = efct->efcport;
16862306a36Sopenharmony_ci
16962306a36Sopenharmony_ci	if (op == 1) {
17062306a36Sopenharmony_ci		tpg->enabled = true;
17162306a36Sopenharmony_ci		efc_log_debug(efct, "enable portal group %d\n", tpg->tpgt);
17262306a36Sopenharmony_ci
17362306a36Sopenharmony_ci		if (efc->domain) {
17462306a36Sopenharmony_ci			int ret;
17562306a36Sopenharmony_ci
17662306a36Sopenharmony_ci			ret = efc_nport_vport_new(efc->domain,
17762306a36Sopenharmony_ci						  lio_vport->npiv_wwpn,
17862306a36Sopenharmony_ci						  lio_vport->npiv_wwnn,
17962306a36Sopenharmony_ci						  U32_MAX, false, true,
18062306a36Sopenharmony_ci						  NULL, NULL);
18162306a36Sopenharmony_ci			if (ret != 0) {
18262306a36Sopenharmony_ci				efc_log_err(efct, "Failed to create Vport\n");
18362306a36Sopenharmony_ci				return ret;
18462306a36Sopenharmony_ci			}
18562306a36Sopenharmony_ci			return count;
18662306a36Sopenharmony_ci		}
18762306a36Sopenharmony_ci
18862306a36Sopenharmony_ci		if (!(efc_vport_create_spec(efc, lio_vport->npiv_wwnn,
18962306a36Sopenharmony_ci					    lio_vport->npiv_wwpn, U32_MAX,
19062306a36Sopenharmony_ci					    false, true, NULL, NULL)))
19162306a36Sopenharmony_ci			return -ENOMEM;
19262306a36Sopenharmony_ci
19362306a36Sopenharmony_ci	} else if (op == 0) {
19462306a36Sopenharmony_ci		efc_log_debug(efct, "disable portal group %d\n", tpg->tpgt);
19562306a36Sopenharmony_ci
19662306a36Sopenharmony_ci		tpg->enabled = false;
19762306a36Sopenharmony_ci		/* only physical nport should exist, free lio_nport
19862306a36Sopenharmony_ci		 * allocated in efct_lio_make_nport
19962306a36Sopenharmony_ci		 */
20062306a36Sopenharmony_ci		if (efc->domain) {
20162306a36Sopenharmony_ci			efc_nport_vport_del(efct->efcport, efc->domain,
20262306a36Sopenharmony_ci					    lio_vport->npiv_wwpn,
20362306a36Sopenharmony_ci					    lio_vport->npiv_wwnn);
20462306a36Sopenharmony_ci			return count;
20562306a36Sopenharmony_ci		}
20662306a36Sopenharmony_ci	} else {
20762306a36Sopenharmony_ci		return -EINVAL;
20862306a36Sopenharmony_ci	}
20962306a36Sopenharmony_ci	return count;
21062306a36Sopenharmony_ci}
21162306a36Sopenharmony_ci
21262306a36Sopenharmony_cistatic char *efct_lio_get_fabric_wwn(struct se_portal_group *se_tpg)
21362306a36Sopenharmony_ci{
21462306a36Sopenharmony_ci	struct efct_lio_tpg *tpg =
21562306a36Sopenharmony_ci		container_of(se_tpg, struct efct_lio_tpg, tpg);
21662306a36Sopenharmony_ci
21762306a36Sopenharmony_ci	return tpg->nport->wwpn_str;
21862306a36Sopenharmony_ci}
21962306a36Sopenharmony_ci
22062306a36Sopenharmony_cistatic char *efct_lio_get_npiv_fabric_wwn(struct se_portal_group *se_tpg)
22162306a36Sopenharmony_ci{
22262306a36Sopenharmony_ci	struct efct_lio_tpg *tpg =
22362306a36Sopenharmony_ci		container_of(se_tpg, struct efct_lio_tpg, tpg);
22462306a36Sopenharmony_ci
22562306a36Sopenharmony_ci	return tpg->vport->wwpn_str;
22662306a36Sopenharmony_ci}
22762306a36Sopenharmony_ci
22862306a36Sopenharmony_cistatic u16 efct_lio_get_tag(struct se_portal_group *se_tpg)
22962306a36Sopenharmony_ci{
23062306a36Sopenharmony_ci	struct efct_lio_tpg *tpg =
23162306a36Sopenharmony_ci		container_of(se_tpg, struct efct_lio_tpg, tpg);
23262306a36Sopenharmony_ci
23362306a36Sopenharmony_ci	return tpg->tpgt;
23462306a36Sopenharmony_ci}
23562306a36Sopenharmony_ci
23662306a36Sopenharmony_cistatic u16 efct_lio_get_npiv_tag(struct se_portal_group *se_tpg)
23762306a36Sopenharmony_ci{
23862306a36Sopenharmony_ci	struct efct_lio_tpg *tpg =
23962306a36Sopenharmony_ci		container_of(se_tpg, struct efct_lio_tpg, tpg);
24062306a36Sopenharmony_ci
24162306a36Sopenharmony_ci	return tpg->tpgt;
24262306a36Sopenharmony_ci}
24362306a36Sopenharmony_ci
24462306a36Sopenharmony_cistatic int efct_lio_check_demo_mode(struct se_portal_group *se_tpg)
24562306a36Sopenharmony_ci{
24662306a36Sopenharmony_ci	return 1;
24762306a36Sopenharmony_ci}
24862306a36Sopenharmony_ci
24962306a36Sopenharmony_cistatic int efct_lio_check_demo_mode_cache(struct se_portal_group *se_tpg)
25062306a36Sopenharmony_ci{
25162306a36Sopenharmony_ci	return 1;
25262306a36Sopenharmony_ci}
25362306a36Sopenharmony_ci
25462306a36Sopenharmony_cistatic int efct_lio_check_demo_write_protect(struct se_portal_group *se_tpg)
25562306a36Sopenharmony_ci{
25662306a36Sopenharmony_ci	struct efct_lio_tpg *tpg =
25762306a36Sopenharmony_ci		container_of(se_tpg, struct efct_lio_tpg, tpg);
25862306a36Sopenharmony_ci
25962306a36Sopenharmony_ci	return tpg->tpg_attrib.demo_mode_write_protect;
26062306a36Sopenharmony_ci}
26162306a36Sopenharmony_ci
26262306a36Sopenharmony_cistatic int
26362306a36Sopenharmony_ciefct_lio_npiv_check_demo_write_protect(struct se_portal_group *se_tpg)
26462306a36Sopenharmony_ci{
26562306a36Sopenharmony_ci	struct efct_lio_tpg *tpg =
26662306a36Sopenharmony_ci		container_of(se_tpg, struct efct_lio_tpg, tpg);
26762306a36Sopenharmony_ci
26862306a36Sopenharmony_ci	return tpg->tpg_attrib.demo_mode_write_protect;
26962306a36Sopenharmony_ci}
27062306a36Sopenharmony_ci
27162306a36Sopenharmony_cistatic int efct_lio_check_prod_write_protect(struct se_portal_group *se_tpg)
27262306a36Sopenharmony_ci{
27362306a36Sopenharmony_ci	struct efct_lio_tpg *tpg =
27462306a36Sopenharmony_ci		container_of(se_tpg, struct efct_lio_tpg, tpg);
27562306a36Sopenharmony_ci
27662306a36Sopenharmony_ci	return tpg->tpg_attrib.prod_mode_write_protect;
27762306a36Sopenharmony_ci}
27862306a36Sopenharmony_ci
27962306a36Sopenharmony_cistatic int
28062306a36Sopenharmony_ciefct_lio_npiv_check_prod_write_protect(struct se_portal_group *se_tpg)
28162306a36Sopenharmony_ci{
28262306a36Sopenharmony_ci	struct efct_lio_tpg *tpg =
28362306a36Sopenharmony_ci		container_of(se_tpg, struct efct_lio_tpg, tpg);
28462306a36Sopenharmony_ci
28562306a36Sopenharmony_ci	return tpg->tpg_attrib.prod_mode_write_protect;
28662306a36Sopenharmony_ci}
28762306a36Sopenharmony_ci
28862306a36Sopenharmony_cistatic int efct_lio_check_stop_free(struct se_cmd *se_cmd)
28962306a36Sopenharmony_ci{
29062306a36Sopenharmony_ci	struct efct_scsi_tgt_io *ocp =
29162306a36Sopenharmony_ci		container_of(se_cmd, struct efct_scsi_tgt_io, cmd);
29262306a36Sopenharmony_ci	struct efct_io *io = container_of(ocp, struct efct_io, tgt_io);
29362306a36Sopenharmony_ci
29462306a36Sopenharmony_ci	efct_set_lio_io_state(io, EFCT_LIO_STATE_TFO_CHK_STOP_FREE);
29562306a36Sopenharmony_ci	return target_put_sess_cmd(se_cmd);
29662306a36Sopenharmony_ci}
29762306a36Sopenharmony_ci
29862306a36Sopenharmony_cistatic int
29962306a36Sopenharmony_ciefct_lio_abort_tgt_cb(struct efct_io *io,
30062306a36Sopenharmony_ci		      enum efct_scsi_io_status scsi_status,
30162306a36Sopenharmony_ci		      u32 flags, void *arg)
30262306a36Sopenharmony_ci{
30362306a36Sopenharmony_ci	efct_lio_io_printf(io, "Abort done, status:%d\n", scsi_status);
30462306a36Sopenharmony_ci	return 0;
30562306a36Sopenharmony_ci}
30662306a36Sopenharmony_ci
30762306a36Sopenharmony_cistatic void
30862306a36Sopenharmony_ciefct_lio_aborted_task(struct se_cmd *se_cmd)
30962306a36Sopenharmony_ci{
31062306a36Sopenharmony_ci	struct efct_scsi_tgt_io *ocp =
31162306a36Sopenharmony_ci		container_of(se_cmd, struct efct_scsi_tgt_io, cmd);
31262306a36Sopenharmony_ci	struct efct_io *io = container_of(ocp, struct efct_io, tgt_io);
31362306a36Sopenharmony_ci
31462306a36Sopenharmony_ci	efct_set_lio_io_state(io, EFCT_LIO_STATE_TFO_ABORTED_TASK);
31562306a36Sopenharmony_ci
31662306a36Sopenharmony_ci	if (ocp->rsp_sent)
31762306a36Sopenharmony_ci		return;
31862306a36Sopenharmony_ci
31962306a36Sopenharmony_ci	/* command has been aborted, cleanup here */
32062306a36Sopenharmony_ci	ocp->aborting = true;
32162306a36Sopenharmony_ci	ocp->err = EFCT_SCSI_STATUS_ABORTED;
32262306a36Sopenharmony_ci	/* terminate the exchange */
32362306a36Sopenharmony_ci	efct_scsi_tgt_abort_io(io, efct_lio_abort_tgt_cb, NULL);
32462306a36Sopenharmony_ci}
32562306a36Sopenharmony_ci
32662306a36Sopenharmony_cistatic void efct_lio_release_cmd(struct se_cmd *se_cmd)
32762306a36Sopenharmony_ci{
32862306a36Sopenharmony_ci	struct efct_scsi_tgt_io *ocp =
32962306a36Sopenharmony_ci		container_of(se_cmd, struct efct_scsi_tgt_io, cmd);
33062306a36Sopenharmony_ci	struct efct_io *io = container_of(ocp, struct efct_io, tgt_io);
33162306a36Sopenharmony_ci	struct efct *efct = io->efct;
33262306a36Sopenharmony_ci
33362306a36Sopenharmony_ci	efct_set_lio_io_state(io, EFCT_LIO_STATE_TFO_RELEASE_CMD);
33462306a36Sopenharmony_ci	efct_set_lio_io_state(io, EFCT_LIO_STATE_SCSI_CMPL_CMD);
33562306a36Sopenharmony_ci	efct_scsi_io_complete(io);
33662306a36Sopenharmony_ci	atomic_sub_return(1, &efct->tgt_efct.ios_in_use);
33762306a36Sopenharmony_ci}
33862306a36Sopenharmony_ci
33962306a36Sopenharmony_cistatic void efct_lio_close_session(struct se_session *se_sess)
34062306a36Sopenharmony_ci{
34162306a36Sopenharmony_ci	struct efc_node *node = se_sess->fabric_sess_ptr;
34262306a36Sopenharmony_ci
34362306a36Sopenharmony_ci	pr_debug("se_sess=%p node=%p", se_sess, node);
34462306a36Sopenharmony_ci
34562306a36Sopenharmony_ci	if (!node) {
34662306a36Sopenharmony_ci		pr_debug("node is NULL");
34762306a36Sopenharmony_ci		return;
34862306a36Sopenharmony_ci	}
34962306a36Sopenharmony_ci
35062306a36Sopenharmony_ci	efc_node_post_shutdown(node, NULL);
35162306a36Sopenharmony_ci}
35262306a36Sopenharmony_ci
35362306a36Sopenharmony_cistatic int efct_lio_get_cmd_state(struct se_cmd *cmd)
35462306a36Sopenharmony_ci{
35562306a36Sopenharmony_ci	struct efct_scsi_tgt_io *ocp =
35662306a36Sopenharmony_ci		container_of(cmd, struct efct_scsi_tgt_io, cmd);
35762306a36Sopenharmony_ci	struct efct_io *io = container_of(ocp, struct efct_io, tgt_io);
35862306a36Sopenharmony_ci
35962306a36Sopenharmony_ci	return io->tgt_io.state;
36062306a36Sopenharmony_ci}
36162306a36Sopenharmony_ci
36262306a36Sopenharmony_cistatic int
36362306a36Sopenharmony_ciefct_lio_sg_map(struct efct_io *io)
36462306a36Sopenharmony_ci{
36562306a36Sopenharmony_ci	struct efct_scsi_tgt_io *ocp = &io->tgt_io;
36662306a36Sopenharmony_ci	struct se_cmd *cmd = &ocp->cmd;
36762306a36Sopenharmony_ci
36862306a36Sopenharmony_ci	ocp->seg_map_cnt = dma_map_sg(&io->efct->pci->dev, cmd->t_data_sg,
36962306a36Sopenharmony_ci				      cmd->t_data_nents, cmd->data_direction);
37062306a36Sopenharmony_ci	if (ocp->seg_map_cnt == 0)
37162306a36Sopenharmony_ci		return -EFAULT;
37262306a36Sopenharmony_ci	return 0;
37362306a36Sopenharmony_ci}
37462306a36Sopenharmony_ci
37562306a36Sopenharmony_cistatic void
37662306a36Sopenharmony_ciefct_lio_sg_unmap(struct efct_io *io)
37762306a36Sopenharmony_ci{
37862306a36Sopenharmony_ci	struct efct_scsi_tgt_io *ocp = &io->tgt_io;
37962306a36Sopenharmony_ci	struct se_cmd *cmd = &ocp->cmd;
38062306a36Sopenharmony_ci
38162306a36Sopenharmony_ci	if (WARN_ON(!ocp->seg_map_cnt || !cmd->t_data_sg))
38262306a36Sopenharmony_ci		return;
38362306a36Sopenharmony_ci
38462306a36Sopenharmony_ci	dma_unmap_sg(&io->efct->pci->dev, cmd->t_data_sg,
38562306a36Sopenharmony_ci		     ocp->seg_map_cnt, cmd->data_direction);
38662306a36Sopenharmony_ci	ocp->seg_map_cnt = 0;
38762306a36Sopenharmony_ci}
38862306a36Sopenharmony_ci
38962306a36Sopenharmony_cistatic int
39062306a36Sopenharmony_ciefct_lio_status_done(struct efct_io *io,
39162306a36Sopenharmony_ci		     enum efct_scsi_io_status scsi_status,
39262306a36Sopenharmony_ci		     u32 flags, void *arg)
39362306a36Sopenharmony_ci{
39462306a36Sopenharmony_ci	struct efct_scsi_tgt_io *ocp = &io->tgt_io;
39562306a36Sopenharmony_ci
39662306a36Sopenharmony_ci	efct_set_lio_io_state(io, EFCT_LIO_STATE_SCSI_RSP_DONE);
39762306a36Sopenharmony_ci	if (scsi_status != EFCT_SCSI_STATUS_GOOD) {
39862306a36Sopenharmony_ci		efct_lio_io_printf(io, "callback completed with error=%d\n",
39962306a36Sopenharmony_ci				   scsi_status);
40062306a36Sopenharmony_ci		ocp->err = scsi_status;
40162306a36Sopenharmony_ci	}
40262306a36Sopenharmony_ci	if (ocp->seg_map_cnt)
40362306a36Sopenharmony_ci		efct_lio_sg_unmap(io);
40462306a36Sopenharmony_ci
40562306a36Sopenharmony_ci	efct_lio_io_printf(io, "status=%d, err=%d flags=0x%x, dir=%d\n",
40662306a36Sopenharmony_ci			   scsi_status, ocp->err, flags, ocp->ddir);
40762306a36Sopenharmony_ci
40862306a36Sopenharmony_ci	efct_set_lio_io_state(io, EFCT_LIO_STATE_TGT_GENERIC_FREE);
40962306a36Sopenharmony_ci	transport_generic_free_cmd(&io->tgt_io.cmd, 0);
41062306a36Sopenharmony_ci	return 0;
41162306a36Sopenharmony_ci}
41262306a36Sopenharmony_ci
41362306a36Sopenharmony_cistatic int
41462306a36Sopenharmony_ciefct_lio_datamove_done(struct efct_io *io, enum efct_scsi_io_status scsi_status,
41562306a36Sopenharmony_ci		       u32 flags, void *arg);
41662306a36Sopenharmony_ci
41762306a36Sopenharmony_cistatic int
41862306a36Sopenharmony_ciefct_lio_write_pending(struct se_cmd *cmd)
41962306a36Sopenharmony_ci{
42062306a36Sopenharmony_ci	struct efct_scsi_tgt_io *ocp =
42162306a36Sopenharmony_ci		container_of(cmd, struct efct_scsi_tgt_io, cmd);
42262306a36Sopenharmony_ci	struct efct_io *io = container_of(ocp, struct efct_io, tgt_io);
42362306a36Sopenharmony_ci	struct efct_scsi_sgl *sgl = io->sgl;
42462306a36Sopenharmony_ci	struct scatterlist *sg;
42562306a36Sopenharmony_ci	u32 flags = 0, cnt, curcnt;
42662306a36Sopenharmony_ci	u64 length = 0;
42762306a36Sopenharmony_ci
42862306a36Sopenharmony_ci	efct_set_lio_io_state(io, EFCT_LIO_STATE_TFO_WRITE_PENDING);
42962306a36Sopenharmony_ci	efct_lio_io_printf(io, "trans_state=0x%x se_cmd_flags=0x%x\n",
43062306a36Sopenharmony_ci			   cmd->transport_state, cmd->se_cmd_flags);
43162306a36Sopenharmony_ci
43262306a36Sopenharmony_ci	if (ocp->seg_cnt == 0) {
43362306a36Sopenharmony_ci		ocp->seg_cnt = cmd->t_data_nents;
43462306a36Sopenharmony_ci		ocp->cur_seg = 0;
43562306a36Sopenharmony_ci		if (efct_lio_sg_map(io)) {
43662306a36Sopenharmony_ci			efct_lio_io_printf(io, "efct_lio_sg_map failed\n");
43762306a36Sopenharmony_ci			return -EFAULT;
43862306a36Sopenharmony_ci		}
43962306a36Sopenharmony_ci	}
44062306a36Sopenharmony_ci	curcnt = (ocp->seg_map_cnt - ocp->cur_seg);
44162306a36Sopenharmony_ci	curcnt = (curcnt < io->sgl_allocated) ? curcnt : io->sgl_allocated;
44262306a36Sopenharmony_ci	/* find current sg */
44362306a36Sopenharmony_ci	for (cnt = 0, sg = cmd->t_data_sg; cnt < ocp->cur_seg; cnt++,
44462306a36Sopenharmony_ci	     sg = sg_next(sg))
44562306a36Sopenharmony_ci		;/* do nothing */
44662306a36Sopenharmony_ci
44762306a36Sopenharmony_ci	for (cnt = 0; cnt < curcnt; cnt++, sg = sg_next(sg)) {
44862306a36Sopenharmony_ci		sgl[cnt].addr = sg_dma_address(sg);
44962306a36Sopenharmony_ci		sgl[cnt].dif_addr = 0;
45062306a36Sopenharmony_ci		sgl[cnt].len = sg_dma_len(sg);
45162306a36Sopenharmony_ci		length += sgl[cnt].len;
45262306a36Sopenharmony_ci		ocp->cur_seg++;
45362306a36Sopenharmony_ci	}
45462306a36Sopenharmony_ci
45562306a36Sopenharmony_ci	if (ocp->cur_seg == ocp->seg_cnt)
45662306a36Sopenharmony_ci		flags = EFCT_SCSI_LAST_DATAPHASE;
45762306a36Sopenharmony_ci
45862306a36Sopenharmony_ci	return efct_scsi_recv_wr_data(io, flags, sgl, curcnt, length,
45962306a36Sopenharmony_ci				    efct_lio_datamove_done, NULL);
46062306a36Sopenharmony_ci}
46162306a36Sopenharmony_ci
46262306a36Sopenharmony_cistatic int
46362306a36Sopenharmony_ciefct_lio_queue_data_in(struct se_cmd *cmd)
46462306a36Sopenharmony_ci{
46562306a36Sopenharmony_ci	struct efct_scsi_tgt_io *ocp =
46662306a36Sopenharmony_ci		container_of(cmd, struct efct_scsi_tgt_io, cmd);
46762306a36Sopenharmony_ci	struct efct_io *io = container_of(ocp, struct efct_io, tgt_io);
46862306a36Sopenharmony_ci	struct efct_scsi_sgl *sgl = io->sgl;
46962306a36Sopenharmony_ci	struct scatterlist *sg = NULL;
47062306a36Sopenharmony_ci	uint flags = 0, cnt = 0, curcnt = 0;
47162306a36Sopenharmony_ci	u64 length = 0;
47262306a36Sopenharmony_ci
47362306a36Sopenharmony_ci	efct_set_lio_io_state(io, EFCT_LIO_STATE_TFO_QUEUE_DATA_IN);
47462306a36Sopenharmony_ci
47562306a36Sopenharmony_ci	if (ocp->seg_cnt == 0) {
47662306a36Sopenharmony_ci		if (cmd->data_length) {
47762306a36Sopenharmony_ci			ocp->seg_cnt = cmd->t_data_nents;
47862306a36Sopenharmony_ci			ocp->cur_seg = 0;
47962306a36Sopenharmony_ci			if (efct_lio_sg_map(io)) {
48062306a36Sopenharmony_ci				efct_lio_io_printf(io,
48162306a36Sopenharmony_ci						   "efct_lio_sg_map failed\n");
48262306a36Sopenharmony_ci				return -EAGAIN;
48362306a36Sopenharmony_ci			}
48462306a36Sopenharmony_ci		} else {
48562306a36Sopenharmony_ci			/* If command length is 0, send the response status */
48662306a36Sopenharmony_ci			struct efct_scsi_cmd_resp rsp;
48762306a36Sopenharmony_ci
48862306a36Sopenharmony_ci			memset(&rsp, 0, sizeof(rsp));
48962306a36Sopenharmony_ci			efct_lio_io_printf(io,
49062306a36Sopenharmony_ci					   "cmd : %p length 0, send status\n",
49162306a36Sopenharmony_ci					   cmd);
49262306a36Sopenharmony_ci			return efct_scsi_send_resp(io, 0, &rsp,
49362306a36Sopenharmony_ci						   efct_lio_status_done, NULL);
49462306a36Sopenharmony_ci		}
49562306a36Sopenharmony_ci	}
49662306a36Sopenharmony_ci	curcnt = min(ocp->seg_map_cnt - ocp->cur_seg, io->sgl_allocated);
49762306a36Sopenharmony_ci
49862306a36Sopenharmony_ci	while (cnt < curcnt) {
49962306a36Sopenharmony_ci		sg = &cmd->t_data_sg[ocp->cur_seg];
50062306a36Sopenharmony_ci		sgl[cnt].addr = sg_dma_address(sg);
50162306a36Sopenharmony_ci		sgl[cnt].dif_addr = 0;
50262306a36Sopenharmony_ci		if (ocp->transferred_len + sg_dma_len(sg) >= cmd->data_length)
50362306a36Sopenharmony_ci			sgl[cnt].len = cmd->data_length - ocp->transferred_len;
50462306a36Sopenharmony_ci		else
50562306a36Sopenharmony_ci			sgl[cnt].len = sg_dma_len(sg);
50662306a36Sopenharmony_ci
50762306a36Sopenharmony_ci		ocp->transferred_len += sgl[cnt].len;
50862306a36Sopenharmony_ci		length += sgl[cnt].len;
50962306a36Sopenharmony_ci		ocp->cur_seg++;
51062306a36Sopenharmony_ci		cnt++;
51162306a36Sopenharmony_ci		if (ocp->transferred_len == cmd->data_length)
51262306a36Sopenharmony_ci			break;
51362306a36Sopenharmony_ci	}
51462306a36Sopenharmony_ci
51562306a36Sopenharmony_ci	if (ocp->transferred_len == cmd->data_length) {
51662306a36Sopenharmony_ci		flags = EFCT_SCSI_LAST_DATAPHASE;
51762306a36Sopenharmony_ci		ocp->seg_cnt = ocp->cur_seg;
51862306a36Sopenharmony_ci	}
51962306a36Sopenharmony_ci
52062306a36Sopenharmony_ci	/* If there is residual, disable Auto Good Response */
52162306a36Sopenharmony_ci	if (cmd->residual_count)
52262306a36Sopenharmony_ci		flags |= EFCT_SCSI_NO_AUTO_RESPONSE;
52362306a36Sopenharmony_ci
52462306a36Sopenharmony_ci	efct_set_lio_io_state(io, EFCT_LIO_STATE_SCSI_SEND_RD_DATA);
52562306a36Sopenharmony_ci
52662306a36Sopenharmony_ci	return efct_scsi_send_rd_data(io, flags, sgl, curcnt, length,
52762306a36Sopenharmony_ci				    efct_lio_datamove_done, NULL);
52862306a36Sopenharmony_ci}
52962306a36Sopenharmony_ci
53062306a36Sopenharmony_cistatic void
53162306a36Sopenharmony_ciefct_lio_send_resp(struct efct_io *io, enum efct_scsi_io_status scsi_status,
53262306a36Sopenharmony_ci		   u32 flags)
53362306a36Sopenharmony_ci{
53462306a36Sopenharmony_ci	struct efct_scsi_cmd_resp rsp;
53562306a36Sopenharmony_ci	struct efct_scsi_tgt_io *ocp = &io->tgt_io;
53662306a36Sopenharmony_ci	struct se_cmd *cmd = &io->tgt_io.cmd;
53762306a36Sopenharmony_ci	int rc;
53862306a36Sopenharmony_ci
53962306a36Sopenharmony_ci	if (flags & EFCT_SCSI_IO_CMPL_RSP_SENT) {
54062306a36Sopenharmony_ci		ocp->rsp_sent = true;
54162306a36Sopenharmony_ci		efct_set_lio_io_state(io, EFCT_LIO_STATE_TGT_GENERIC_FREE);
54262306a36Sopenharmony_ci		transport_generic_free_cmd(&io->tgt_io.cmd, 0);
54362306a36Sopenharmony_ci		return;
54462306a36Sopenharmony_ci	}
54562306a36Sopenharmony_ci
54662306a36Sopenharmony_ci	/* send check condition if an error occurred */
54762306a36Sopenharmony_ci	memset(&rsp, 0, sizeof(rsp));
54862306a36Sopenharmony_ci	rsp.scsi_status = cmd->scsi_status;
54962306a36Sopenharmony_ci	rsp.sense_data = (uint8_t *)io->tgt_io.sense_buffer;
55062306a36Sopenharmony_ci	rsp.sense_data_length = cmd->scsi_sense_length;
55162306a36Sopenharmony_ci
55262306a36Sopenharmony_ci	/* Check for residual underrun or overrun */
55362306a36Sopenharmony_ci	if (cmd->se_cmd_flags & SCF_OVERFLOW_BIT)
55462306a36Sopenharmony_ci		rsp.residual = -cmd->residual_count;
55562306a36Sopenharmony_ci	else if (cmd->se_cmd_flags & SCF_UNDERFLOW_BIT)
55662306a36Sopenharmony_ci		rsp.residual = cmd->residual_count;
55762306a36Sopenharmony_ci
55862306a36Sopenharmony_ci	rc = efct_scsi_send_resp(io, 0, &rsp, efct_lio_status_done, NULL);
55962306a36Sopenharmony_ci	efct_set_lio_io_state(io, EFCT_LIO_STATE_SCSI_SEND_RSP);
56062306a36Sopenharmony_ci	if (rc != 0) {
56162306a36Sopenharmony_ci		efct_lio_io_printf(io, "Read done, send rsp failed %d\n", rc);
56262306a36Sopenharmony_ci		efct_set_lio_io_state(io, EFCT_LIO_STATE_TGT_GENERIC_FREE);
56362306a36Sopenharmony_ci		transport_generic_free_cmd(&io->tgt_io.cmd, 0);
56462306a36Sopenharmony_ci	} else {
56562306a36Sopenharmony_ci		ocp->rsp_sent = true;
56662306a36Sopenharmony_ci	}
56762306a36Sopenharmony_ci}
56862306a36Sopenharmony_ci
56962306a36Sopenharmony_cistatic int
57062306a36Sopenharmony_ciefct_lio_datamove_done(struct efct_io *io, enum efct_scsi_io_status scsi_status,
57162306a36Sopenharmony_ci		       u32 flags, void *arg)
57262306a36Sopenharmony_ci{
57362306a36Sopenharmony_ci	struct efct_scsi_tgt_io *ocp = &io->tgt_io;
57462306a36Sopenharmony_ci
57562306a36Sopenharmony_ci	efct_set_lio_io_state(io, EFCT_LIO_STATE_SCSI_DATA_DONE);
57662306a36Sopenharmony_ci	if (scsi_status != EFCT_SCSI_STATUS_GOOD) {
57762306a36Sopenharmony_ci		efct_lio_io_printf(io, "callback completed with error=%d\n",
57862306a36Sopenharmony_ci				   scsi_status);
57962306a36Sopenharmony_ci		ocp->err = scsi_status;
58062306a36Sopenharmony_ci	}
58162306a36Sopenharmony_ci	efct_lio_io_printf(io, "seg_map_cnt=%d\n", ocp->seg_map_cnt);
58262306a36Sopenharmony_ci	if (ocp->seg_map_cnt) {
58362306a36Sopenharmony_ci		if (ocp->err == EFCT_SCSI_STATUS_GOOD &&
58462306a36Sopenharmony_ci		    ocp->cur_seg < ocp->seg_cnt) {
58562306a36Sopenharmony_ci			int rc;
58662306a36Sopenharmony_ci
58762306a36Sopenharmony_ci			efct_lio_io_printf(io, "continuing cmd at segm=%d\n",
58862306a36Sopenharmony_ci					   ocp->cur_seg);
58962306a36Sopenharmony_ci			if (ocp->ddir == DMA_TO_DEVICE)
59062306a36Sopenharmony_ci				rc = efct_lio_write_pending(&ocp->cmd);
59162306a36Sopenharmony_ci			else
59262306a36Sopenharmony_ci				rc = efct_lio_queue_data_in(&ocp->cmd);
59362306a36Sopenharmony_ci			if (!rc)
59462306a36Sopenharmony_ci				return 0;
59562306a36Sopenharmony_ci
59662306a36Sopenharmony_ci			ocp->err = EFCT_SCSI_STATUS_ERROR;
59762306a36Sopenharmony_ci			efct_lio_io_printf(io, "could not continue command\n");
59862306a36Sopenharmony_ci		}
59962306a36Sopenharmony_ci		efct_lio_sg_unmap(io);
60062306a36Sopenharmony_ci	}
60162306a36Sopenharmony_ci
60262306a36Sopenharmony_ci	if (io->tgt_io.aborting) {
60362306a36Sopenharmony_ci		efct_lio_io_printf(io, "IO done aborted\n");
60462306a36Sopenharmony_ci		return 0;
60562306a36Sopenharmony_ci	}
60662306a36Sopenharmony_ci
60762306a36Sopenharmony_ci	if (ocp->ddir == DMA_TO_DEVICE) {
60862306a36Sopenharmony_ci		efct_lio_io_printf(io, "Write done, trans_state=0x%x\n",
60962306a36Sopenharmony_ci				   io->tgt_io.cmd.transport_state);
61062306a36Sopenharmony_ci		if (scsi_status != EFCT_SCSI_STATUS_GOOD) {
61162306a36Sopenharmony_ci			transport_generic_request_failure(&io->tgt_io.cmd,
61262306a36Sopenharmony_ci					TCM_CHECK_CONDITION_ABORT_CMD);
61362306a36Sopenharmony_ci			efct_set_lio_io_state(io,
61462306a36Sopenharmony_ci				EFCT_LIO_STATE_TGT_GENERIC_REQ_FAILURE);
61562306a36Sopenharmony_ci		} else {
61662306a36Sopenharmony_ci			efct_set_lio_io_state(io,
61762306a36Sopenharmony_ci						EFCT_LIO_STATE_TGT_EXECUTE_CMD);
61862306a36Sopenharmony_ci			target_execute_cmd(&io->tgt_io.cmd);
61962306a36Sopenharmony_ci		}
62062306a36Sopenharmony_ci	} else {
62162306a36Sopenharmony_ci		efct_lio_send_resp(io, scsi_status, flags);
62262306a36Sopenharmony_ci	}
62362306a36Sopenharmony_ci	return 0;
62462306a36Sopenharmony_ci}
62562306a36Sopenharmony_ci
62662306a36Sopenharmony_cistatic int
62762306a36Sopenharmony_ciefct_lio_tmf_done(struct efct_io *io, enum efct_scsi_io_status scsi_status,
62862306a36Sopenharmony_ci		  u32 flags, void *arg)
62962306a36Sopenharmony_ci{
63062306a36Sopenharmony_ci	efct_lio_tmfio_printf(io, "cmd=%p status=%d, flags=0x%x\n",
63162306a36Sopenharmony_ci			      &io->tgt_io.cmd, scsi_status, flags);
63262306a36Sopenharmony_ci
63362306a36Sopenharmony_ci	efct_set_lio_io_state(io, EFCT_LIO_STATE_TGT_GENERIC_FREE);
63462306a36Sopenharmony_ci	transport_generic_free_cmd(&io->tgt_io.cmd, 0);
63562306a36Sopenharmony_ci	return 0;
63662306a36Sopenharmony_ci}
63762306a36Sopenharmony_ci
63862306a36Sopenharmony_cistatic int
63962306a36Sopenharmony_ciefct_lio_null_tmf_done(struct efct_io *tmfio,
64062306a36Sopenharmony_ci		       enum efct_scsi_io_status scsi_status,
64162306a36Sopenharmony_ci		      u32 flags, void *arg)
64262306a36Sopenharmony_ci{
64362306a36Sopenharmony_ci	efct_lio_tmfio_printf(tmfio, "cmd=%p status=%d, flags=0x%x\n",
64462306a36Sopenharmony_ci			      &tmfio->tgt_io.cmd, scsi_status, flags);
64562306a36Sopenharmony_ci
64662306a36Sopenharmony_ci	/* free struct efct_io only, no active se_cmd */
64762306a36Sopenharmony_ci	efct_scsi_io_complete(tmfio);
64862306a36Sopenharmony_ci	return 0;
64962306a36Sopenharmony_ci}
65062306a36Sopenharmony_ci
65162306a36Sopenharmony_cistatic int
65262306a36Sopenharmony_ciefct_lio_queue_status(struct se_cmd *cmd)
65362306a36Sopenharmony_ci{
65462306a36Sopenharmony_ci	struct efct_scsi_cmd_resp rsp;
65562306a36Sopenharmony_ci	struct efct_scsi_tgt_io *ocp =
65662306a36Sopenharmony_ci		container_of(cmd, struct efct_scsi_tgt_io, cmd);
65762306a36Sopenharmony_ci	struct efct_io *io = container_of(ocp, struct efct_io, tgt_io);
65862306a36Sopenharmony_ci	int rc = 0;
65962306a36Sopenharmony_ci
66062306a36Sopenharmony_ci	efct_set_lio_io_state(io, EFCT_LIO_STATE_TFO_QUEUE_STATUS);
66162306a36Sopenharmony_ci	efct_lio_io_printf(io,
66262306a36Sopenharmony_ci		"status=0x%x trans_state=0x%x se_cmd_flags=0x%x sns_len=%d\n",
66362306a36Sopenharmony_ci		cmd->scsi_status, cmd->transport_state, cmd->se_cmd_flags,
66462306a36Sopenharmony_ci		cmd->scsi_sense_length);
66562306a36Sopenharmony_ci
66662306a36Sopenharmony_ci	memset(&rsp, 0, sizeof(rsp));
66762306a36Sopenharmony_ci	rsp.scsi_status = cmd->scsi_status;
66862306a36Sopenharmony_ci	rsp.sense_data = (u8 *)io->tgt_io.sense_buffer;
66962306a36Sopenharmony_ci	rsp.sense_data_length = cmd->scsi_sense_length;
67062306a36Sopenharmony_ci
67162306a36Sopenharmony_ci	/* Check for residual underrun or overrun, mark negitive value for
67262306a36Sopenharmony_ci	 * underrun to recognize in HW
67362306a36Sopenharmony_ci	 */
67462306a36Sopenharmony_ci	if (cmd->se_cmd_flags & SCF_OVERFLOW_BIT)
67562306a36Sopenharmony_ci		rsp.residual = -cmd->residual_count;
67662306a36Sopenharmony_ci	else if (cmd->se_cmd_flags & SCF_UNDERFLOW_BIT)
67762306a36Sopenharmony_ci		rsp.residual = cmd->residual_count;
67862306a36Sopenharmony_ci
67962306a36Sopenharmony_ci	rc = efct_scsi_send_resp(io, 0, &rsp, efct_lio_status_done, NULL);
68062306a36Sopenharmony_ci	efct_set_lio_io_state(io, EFCT_LIO_STATE_SCSI_SEND_RSP);
68162306a36Sopenharmony_ci	if (rc == 0)
68262306a36Sopenharmony_ci		ocp->rsp_sent = true;
68362306a36Sopenharmony_ci	return rc;
68462306a36Sopenharmony_ci}
68562306a36Sopenharmony_ci
68662306a36Sopenharmony_cistatic void efct_lio_queue_tm_rsp(struct se_cmd *cmd)
68762306a36Sopenharmony_ci{
68862306a36Sopenharmony_ci	struct efct_scsi_tgt_io *ocp =
68962306a36Sopenharmony_ci		container_of(cmd, struct efct_scsi_tgt_io, cmd);
69062306a36Sopenharmony_ci	struct efct_io *tmfio = container_of(ocp, struct efct_io, tgt_io);
69162306a36Sopenharmony_ci	struct se_tmr_req *se_tmr = cmd->se_tmr_req;
69262306a36Sopenharmony_ci	u8 rspcode;
69362306a36Sopenharmony_ci
69462306a36Sopenharmony_ci	efct_lio_tmfio_printf(tmfio, "cmd=%p function=0x%x tmr->response=%d\n",
69562306a36Sopenharmony_ci			      cmd, se_tmr->function, se_tmr->response);
69662306a36Sopenharmony_ci	switch (se_tmr->response) {
69762306a36Sopenharmony_ci	case TMR_FUNCTION_COMPLETE:
69862306a36Sopenharmony_ci		rspcode = EFCT_SCSI_TMF_FUNCTION_COMPLETE;
69962306a36Sopenharmony_ci		break;
70062306a36Sopenharmony_ci	case TMR_TASK_DOES_NOT_EXIST:
70162306a36Sopenharmony_ci		rspcode = EFCT_SCSI_TMF_FUNCTION_IO_NOT_FOUND;
70262306a36Sopenharmony_ci		break;
70362306a36Sopenharmony_ci	case TMR_LUN_DOES_NOT_EXIST:
70462306a36Sopenharmony_ci		rspcode = EFCT_SCSI_TMF_INCORRECT_LOGICAL_UNIT_NUMBER;
70562306a36Sopenharmony_ci		break;
70662306a36Sopenharmony_ci	case TMR_FUNCTION_REJECTED:
70762306a36Sopenharmony_ci	default:
70862306a36Sopenharmony_ci		rspcode = EFCT_SCSI_TMF_FUNCTION_REJECTED;
70962306a36Sopenharmony_ci		break;
71062306a36Sopenharmony_ci	}
71162306a36Sopenharmony_ci	efct_scsi_send_tmf_resp(tmfio, rspcode, NULL, efct_lio_tmf_done, NULL);
71262306a36Sopenharmony_ci}
71362306a36Sopenharmony_ci
71462306a36Sopenharmony_cistatic struct efct *efct_find_wwpn(u64 wwpn)
71562306a36Sopenharmony_ci{
71662306a36Sopenharmony_ci	struct efct *efct;
71762306a36Sopenharmony_ci
71862306a36Sopenharmony_ci	 /* Search for the HBA that has this WWPN */
71962306a36Sopenharmony_ci	list_for_each_entry(efct, &efct_devices, list_entry) {
72062306a36Sopenharmony_ci
72162306a36Sopenharmony_ci		if (wwpn == efct_get_wwpn(&efct->hw))
72262306a36Sopenharmony_ci			return efct;
72362306a36Sopenharmony_ci	}
72462306a36Sopenharmony_ci
72562306a36Sopenharmony_ci	return NULL;
72662306a36Sopenharmony_ci}
72762306a36Sopenharmony_ci
72862306a36Sopenharmony_cistatic struct se_wwn *
72962306a36Sopenharmony_ciefct_lio_make_nport(struct target_fabric_configfs *tf,
73062306a36Sopenharmony_ci		    struct config_group *group, const char *name)
73162306a36Sopenharmony_ci{
73262306a36Sopenharmony_ci	struct efct_lio_nport *lio_nport;
73362306a36Sopenharmony_ci	struct efct *efct;
73462306a36Sopenharmony_ci	int ret;
73562306a36Sopenharmony_ci	u64 wwpn;
73662306a36Sopenharmony_ci
73762306a36Sopenharmony_ci	ret = efct_lio_parse_wwn(name, &wwpn, 0);
73862306a36Sopenharmony_ci	if (ret)
73962306a36Sopenharmony_ci		return ERR_PTR(ret);
74062306a36Sopenharmony_ci
74162306a36Sopenharmony_ci	efct = efct_find_wwpn(wwpn);
74262306a36Sopenharmony_ci	if (!efct) {
74362306a36Sopenharmony_ci		pr_err("cannot find EFCT for base wwpn %s\n", name);
74462306a36Sopenharmony_ci		return ERR_PTR(-ENXIO);
74562306a36Sopenharmony_ci	}
74662306a36Sopenharmony_ci
74762306a36Sopenharmony_ci	lio_nport = kzalloc(sizeof(*lio_nport), GFP_KERNEL);
74862306a36Sopenharmony_ci	if (!lio_nport)
74962306a36Sopenharmony_ci		return ERR_PTR(-ENOMEM);
75062306a36Sopenharmony_ci
75162306a36Sopenharmony_ci	lio_nport->efct = efct;
75262306a36Sopenharmony_ci	lio_nport->wwpn = wwpn;
75362306a36Sopenharmony_ci	efct_format_wwn(lio_nport->wwpn_str, sizeof(lio_nport->wwpn_str),
75462306a36Sopenharmony_ci			"naa.", wwpn);
75562306a36Sopenharmony_ci	efct->tgt_efct.lio_nport = lio_nport;
75662306a36Sopenharmony_ci
75762306a36Sopenharmony_ci	return &lio_nport->nport_wwn;
75862306a36Sopenharmony_ci}
75962306a36Sopenharmony_ci
76062306a36Sopenharmony_cistatic struct se_wwn *
76162306a36Sopenharmony_ciefct_lio_npiv_make_nport(struct target_fabric_configfs *tf,
76262306a36Sopenharmony_ci			 struct config_group *group, const char *name)
76362306a36Sopenharmony_ci{
76462306a36Sopenharmony_ci	struct efct_lio_vport *lio_vport;
76562306a36Sopenharmony_ci	struct efct *efct;
76662306a36Sopenharmony_ci	int ret;
76762306a36Sopenharmony_ci	u64 p_wwpn, npiv_wwpn, npiv_wwnn;
76862306a36Sopenharmony_ci	char *p, *pbuf, tmp[128];
76962306a36Sopenharmony_ci	struct efct_lio_vport_list_t *vport_list;
77062306a36Sopenharmony_ci	struct fc_vport *new_fc_vport;
77162306a36Sopenharmony_ci	struct fc_vport_identifiers vport_id;
77262306a36Sopenharmony_ci	unsigned long flags = 0;
77362306a36Sopenharmony_ci
77462306a36Sopenharmony_ci	snprintf(tmp, sizeof(tmp), "%s", name);
77562306a36Sopenharmony_ci	pbuf = &tmp[0];
77662306a36Sopenharmony_ci
77762306a36Sopenharmony_ci	p = strsep(&pbuf, "@");
77862306a36Sopenharmony_ci
77962306a36Sopenharmony_ci	if (!p || !pbuf) {
78062306a36Sopenharmony_ci		pr_err("Unable to find separator operator(@)\n");
78162306a36Sopenharmony_ci		return ERR_PTR(-EINVAL);
78262306a36Sopenharmony_ci	}
78362306a36Sopenharmony_ci
78462306a36Sopenharmony_ci	ret = efct_lio_parse_wwn(p, &p_wwpn, 0);
78562306a36Sopenharmony_ci	if (ret)
78662306a36Sopenharmony_ci		return ERR_PTR(ret);
78762306a36Sopenharmony_ci
78862306a36Sopenharmony_ci	ret = efct_lio_parse_npiv_wwn(pbuf, strlen(pbuf), &npiv_wwpn,
78962306a36Sopenharmony_ci				      &npiv_wwnn);
79062306a36Sopenharmony_ci	if (ret)
79162306a36Sopenharmony_ci		return ERR_PTR(ret);
79262306a36Sopenharmony_ci
79362306a36Sopenharmony_ci	efct = efct_find_wwpn(p_wwpn);
79462306a36Sopenharmony_ci	if (!efct) {
79562306a36Sopenharmony_ci		pr_err("cannot find EFCT for base wwpn %s\n", name);
79662306a36Sopenharmony_ci		return ERR_PTR(-ENXIO);
79762306a36Sopenharmony_ci	}
79862306a36Sopenharmony_ci
79962306a36Sopenharmony_ci	lio_vport = kzalloc(sizeof(*lio_vport), GFP_KERNEL);
80062306a36Sopenharmony_ci	if (!lio_vport)
80162306a36Sopenharmony_ci		return ERR_PTR(-ENOMEM);
80262306a36Sopenharmony_ci
80362306a36Sopenharmony_ci	lio_vport->efct = efct;
80462306a36Sopenharmony_ci	lio_vport->wwpn = p_wwpn;
80562306a36Sopenharmony_ci	lio_vport->npiv_wwpn = npiv_wwpn;
80662306a36Sopenharmony_ci	lio_vport->npiv_wwnn = npiv_wwnn;
80762306a36Sopenharmony_ci
80862306a36Sopenharmony_ci	efct_format_wwn(lio_vport->wwpn_str, sizeof(lio_vport->wwpn_str),
80962306a36Sopenharmony_ci			"naa.", npiv_wwpn);
81062306a36Sopenharmony_ci
81162306a36Sopenharmony_ci	vport_list = kzalloc(sizeof(*vport_list), GFP_KERNEL);
81262306a36Sopenharmony_ci	if (!vport_list) {
81362306a36Sopenharmony_ci		kfree(lio_vport);
81462306a36Sopenharmony_ci		return ERR_PTR(-ENOMEM);
81562306a36Sopenharmony_ci	}
81662306a36Sopenharmony_ci
81762306a36Sopenharmony_ci	vport_list->lio_vport = lio_vport;
81862306a36Sopenharmony_ci
81962306a36Sopenharmony_ci	memset(&vport_id, 0, sizeof(vport_id));
82062306a36Sopenharmony_ci	vport_id.port_name = npiv_wwpn;
82162306a36Sopenharmony_ci	vport_id.node_name = npiv_wwnn;
82262306a36Sopenharmony_ci	vport_id.roles = FC_PORT_ROLE_FCP_INITIATOR;
82362306a36Sopenharmony_ci	vport_id.vport_type = FC_PORTTYPE_NPIV;
82462306a36Sopenharmony_ci	vport_id.disable = false;
82562306a36Sopenharmony_ci
82662306a36Sopenharmony_ci	new_fc_vport = fc_vport_create(efct->shost, 0, &vport_id);
82762306a36Sopenharmony_ci	if (!new_fc_vport) {
82862306a36Sopenharmony_ci		efc_log_err(efct, "fc_vport_create failed\n");
82962306a36Sopenharmony_ci		kfree(lio_vport);
83062306a36Sopenharmony_ci		kfree(vport_list);
83162306a36Sopenharmony_ci		return ERR_PTR(-ENOMEM);
83262306a36Sopenharmony_ci	}
83362306a36Sopenharmony_ci
83462306a36Sopenharmony_ci	lio_vport->fc_vport = new_fc_vport;
83562306a36Sopenharmony_ci	spin_lock_irqsave(&efct->tgt_efct.efct_lio_lock, flags);
83662306a36Sopenharmony_ci	INIT_LIST_HEAD(&vport_list->list_entry);
83762306a36Sopenharmony_ci	list_add_tail(&vport_list->list_entry, &efct->tgt_efct.vport_list);
83862306a36Sopenharmony_ci	spin_unlock_irqrestore(&efct->tgt_efct.efct_lio_lock, flags);
83962306a36Sopenharmony_ci
84062306a36Sopenharmony_ci	return &lio_vport->vport_wwn;
84162306a36Sopenharmony_ci}
84262306a36Sopenharmony_ci
84362306a36Sopenharmony_cistatic void
84462306a36Sopenharmony_ciefct_lio_drop_nport(struct se_wwn *wwn)
84562306a36Sopenharmony_ci{
84662306a36Sopenharmony_ci	struct efct_lio_nport *lio_nport =
84762306a36Sopenharmony_ci		container_of(wwn, struct efct_lio_nport, nport_wwn);
84862306a36Sopenharmony_ci	struct efct *efct = lio_nport->efct;
84962306a36Sopenharmony_ci
85062306a36Sopenharmony_ci	/* only physical nport should exist, free lio_nport allocated
85162306a36Sopenharmony_ci	 * in efct_lio_make_nport.
85262306a36Sopenharmony_ci	 */
85362306a36Sopenharmony_ci	kfree(efct->tgt_efct.lio_nport);
85462306a36Sopenharmony_ci	efct->tgt_efct.lio_nport = NULL;
85562306a36Sopenharmony_ci}
85662306a36Sopenharmony_ci
85762306a36Sopenharmony_cistatic void
85862306a36Sopenharmony_ciefct_lio_npiv_drop_nport(struct se_wwn *wwn)
85962306a36Sopenharmony_ci{
86062306a36Sopenharmony_ci	struct efct_lio_vport *lio_vport =
86162306a36Sopenharmony_ci		container_of(wwn, struct efct_lio_vport, vport_wwn);
86262306a36Sopenharmony_ci	struct efct_lio_vport_list_t *vport, *next_vport;
86362306a36Sopenharmony_ci	struct efct *efct = lio_vport->efct;
86462306a36Sopenharmony_ci	unsigned long flags = 0;
86562306a36Sopenharmony_ci
86662306a36Sopenharmony_ci	if (lio_vport->fc_vport)
86762306a36Sopenharmony_ci		fc_vport_terminate(lio_vport->fc_vport);
86862306a36Sopenharmony_ci
86962306a36Sopenharmony_ci	spin_lock_irqsave(&efct->tgt_efct.efct_lio_lock, flags);
87062306a36Sopenharmony_ci
87162306a36Sopenharmony_ci	list_for_each_entry_safe(vport, next_vport, &efct->tgt_efct.vport_list,
87262306a36Sopenharmony_ci				 list_entry) {
87362306a36Sopenharmony_ci		if (vport->lio_vport == lio_vport) {
87462306a36Sopenharmony_ci			list_del(&vport->list_entry);
87562306a36Sopenharmony_ci			kfree(vport->lio_vport);
87662306a36Sopenharmony_ci			kfree(vport);
87762306a36Sopenharmony_ci			break;
87862306a36Sopenharmony_ci		}
87962306a36Sopenharmony_ci	}
88062306a36Sopenharmony_ci	spin_unlock_irqrestore(&efct->tgt_efct.efct_lio_lock, flags);
88162306a36Sopenharmony_ci}
88262306a36Sopenharmony_ci
88362306a36Sopenharmony_cistatic struct se_portal_group *
88462306a36Sopenharmony_ciefct_lio_make_tpg(struct se_wwn *wwn, const char *name)
88562306a36Sopenharmony_ci{
88662306a36Sopenharmony_ci	struct efct_lio_nport *lio_nport =
88762306a36Sopenharmony_ci		container_of(wwn, struct efct_lio_nport, nport_wwn);
88862306a36Sopenharmony_ci	struct efct_lio_tpg *tpg;
88962306a36Sopenharmony_ci	struct efct *efct;
89062306a36Sopenharmony_ci	unsigned long n;
89162306a36Sopenharmony_ci	int ret;
89262306a36Sopenharmony_ci
89362306a36Sopenharmony_ci	if (strstr(name, "tpgt_") != name)
89462306a36Sopenharmony_ci		return ERR_PTR(-EINVAL);
89562306a36Sopenharmony_ci	if (kstrtoul(name + 5, 10, &n) || n > USHRT_MAX)
89662306a36Sopenharmony_ci		return ERR_PTR(-EINVAL);
89762306a36Sopenharmony_ci
89862306a36Sopenharmony_ci	tpg = kzalloc(sizeof(*tpg), GFP_KERNEL);
89962306a36Sopenharmony_ci	if (!tpg)
90062306a36Sopenharmony_ci		return ERR_PTR(-ENOMEM);
90162306a36Sopenharmony_ci
90262306a36Sopenharmony_ci	tpg->nport = lio_nport;
90362306a36Sopenharmony_ci	tpg->tpgt = n;
90462306a36Sopenharmony_ci	tpg->enabled = false;
90562306a36Sopenharmony_ci
90662306a36Sopenharmony_ci	tpg->tpg_attrib.generate_node_acls = 1;
90762306a36Sopenharmony_ci	tpg->tpg_attrib.demo_mode_write_protect = 1;
90862306a36Sopenharmony_ci	tpg->tpg_attrib.cache_dynamic_acls = 1;
90962306a36Sopenharmony_ci	tpg->tpg_attrib.demo_mode_login_only = 1;
91062306a36Sopenharmony_ci	tpg->tpg_attrib.session_deletion_wait = 1;
91162306a36Sopenharmony_ci
91262306a36Sopenharmony_ci	ret = core_tpg_register(wwn, &tpg->tpg, SCSI_PROTOCOL_FCP);
91362306a36Sopenharmony_ci	if (ret < 0) {
91462306a36Sopenharmony_ci		kfree(tpg);
91562306a36Sopenharmony_ci		return NULL;
91662306a36Sopenharmony_ci	}
91762306a36Sopenharmony_ci	efct = lio_nport->efct;
91862306a36Sopenharmony_ci	efct->tgt_efct.tpg = tpg;
91962306a36Sopenharmony_ci	efc_log_debug(efct, "create portal group %d\n", tpg->tpgt);
92062306a36Sopenharmony_ci
92162306a36Sopenharmony_ci	xa_init(&efct->lookup);
92262306a36Sopenharmony_ci	return &tpg->tpg;
92362306a36Sopenharmony_ci}
92462306a36Sopenharmony_ci
92562306a36Sopenharmony_cistatic void
92662306a36Sopenharmony_ciefct_lio_drop_tpg(struct se_portal_group *se_tpg)
92762306a36Sopenharmony_ci{
92862306a36Sopenharmony_ci	struct efct_lio_tpg *tpg =
92962306a36Sopenharmony_ci		container_of(se_tpg, struct efct_lio_tpg, tpg);
93062306a36Sopenharmony_ci
93162306a36Sopenharmony_ci	struct efct *efct = tpg->nport->efct;
93262306a36Sopenharmony_ci
93362306a36Sopenharmony_ci	efc_log_debug(efct, "drop portal group %d\n", tpg->tpgt);
93462306a36Sopenharmony_ci	tpg->nport->efct->tgt_efct.tpg = NULL;
93562306a36Sopenharmony_ci	core_tpg_deregister(se_tpg);
93662306a36Sopenharmony_ci	xa_destroy(&efct->lookup);
93762306a36Sopenharmony_ci	kfree(tpg);
93862306a36Sopenharmony_ci}
93962306a36Sopenharmony_ci
94062306a36Sopenharmony_cistatic struct se_portal_group *
94162306a36Sopenharmony_ciefct_lio_npiv_make_tpg(struct se_wwn *wwn, const char *name)
94262306a36Sopenharmony_ci{
94362306a36Sopenharmony_ci	struct efct_lio_vport *lio_vport =
94462306a36Sopenharmony_ci		container_of(wwn, struct efct_lio_vport, vport_wwn);
94562306a36Sopenharmony_ci	struct efct_lio_tpg *tpg;
94662306a36Sopenharmony_ci	struct efct *efct;
94762306a36Sopenharmony_ci	unsigned long n;
94862306a36Sopenharmony_ci	int ret;
94962306a36Sopenharmony_ci
95062306a36Sopenharmony_ci	efct = lio_vport->efct;
95162306a36Sopenharmony_ci	if (strstr(name, "tpgt_") != name)
95262306a36Sopenharmony_ci		return ERR_PTR(-EINVAL);
95362306a36Sopenharmony_ci	if (kstrtoul(name + 5, 10, &n) || n > USHRT_MAX)
95462306a36Sopenharmony_ci		return ERR_PTR(-EINVAL);
95562306a36Sopenharmony_ci
95662306a36Sopenharmony_ci	if (n != 1) {
95762306a36Sopenharmony_ci		efc_log_err(efct, "Invalid tpgt index: %ld provided\n", n);
95862306a36Sopenharmony_ci		return ERR_PTR(-EINVAL);
95962306a36Sopenharmony_ci	}
96062306a36Sopenharmony_ci
96162306a36Sopenharmony_ci	tpg = kzalloc(sizeof(*tpg), GFP_KERNEL);
96262306a36Sopenharmony_ci	if (!tpg)
96362306a36Sopenharmony_ci		return ERR_PTR(-ENOMEM);
96462306a36Sopenharmony_ci
96562306a36Sopenharmony_ci	tpg->vport = lio_vport;
96662306a36Sopenharmony_ci	tpg->tpgt = n;
96762306a36Sopenharmony_ci	tpg->enabled = false;
96862306a36Sopenharmony_ci
96962306a36Sopenharmony_ci	tpg->tpg_attrib.generate_node_acls = 1;
97062306a36Sopenharmony_ci	tpg->tpg_attrib.demo_mode_write_protect = 1;
97162306a36Sopenharmony_ci	tpg->tpg_attrib.cache_dynamic_acls = 1;
97262306a36Sopenharmony_ci	tpg->tpg_attrib.demo_mode_login_only = 1;
97362306a36Sopenharmony_ci	tpg->tpg_attrib.session_deletion_wait = 1;
97462306a36Sopenharmony_ci
97562306a36Sopenharmony_ci	ret = core_tpg_register(wwn, &tpg->tpg, SCSI_PROTOCOL_FCP);
97662306a36Sopenharmony_ci
97762306a36Sopenharmony_ci	if (ret < 0) {
97862306a36Sopenharmony_ci		kfree(tpg);
97962306a36Sopenharmony_ci		return NULL;
98062306a36Sopenharmony_ci	}
98162306a36Sopenharmony_ci	lio_vport->tpg = tpg;
98262306a36Sopenharmony_ci	efc_log_debug(efct, "create vport portal group %d\n", tpg->tpgt);
98362306a36Sopenharmony_ci
98462306a36Sopenharmony_ci	return &tpg->tpg;
98562306a36Sopenharmony_ci}
98662306a36Sopenharmony_ci
98762306a36Sopenharmony_cistatic void
98862306a36Sopenharmony_ciefct_lio_npiv_drop_tpg(struct se_portal_group *se_tpg)
98962306a36Sopenharmony_ci{
99062306a36Sopenharmony_ci	struct efct_lio_tpg *tpg =
99162306a36Sopenharmony_ci		container_of(se_tpg, struct efct_lio_tpg, tpg);
99262306a36Sopenharmony_ci
99362306a36Sopenharmony_ci	efc_log_debug(tpg->vport->efct, "drop npiv portal group %d\n",
99462306a36Sopenharmony_ci		       tpg->tpgt);
99562306a36Sopenharmony_ci	core_tpg_deregister(se_tpg);
99662306a36Sopenharmony_ci	kfree(tpg);
99762306a36Sopenharmony_ci}
99862306a36Sopenharmony_ci
99962306a36Sopenharmony_cistatic int
100062306a36Sopenharmony_ciefct_lio_init_nodeacl(struct se_node_acl *se_nacl, const char *name)
100162306a36Sopenharmony_ci{
100262306a36Sopenharmony_ci	struct efct_lio_nacl *nacl;
100362306a36Sopenharmony_ci	u64 wwnn;
100462306a36Sopenharmony_ci
100562306a36Sopenharmony_ci	if (efct_lio_parse_wwn(name, &wwnn, 0) < 0)
100662306a36Sopenharmony_ci		return -EINVAL;
100762306a36Sopenharmony_ci
100862306a36Sopenharmony_ci	nacl = container_of(se_nacl, struct efct_lio_nacl, se_node_acl);
100962306a36Sopenharmony_ci	nacl->nport_wwnn = wwnn;
101062306a36Sopenharmony_ci
101162306a36Sopenharmony_ci	efct_format_wwn(nacl->nport_name, sizeof(nacl->nport_name), "", wwnn);
101262306a36Sopenharmony_ci	return 0;
101362306a36Sopenharmony_ci}
101462306a36Sopenharmony_ci
101562306a36Sopenharmony_cistatic int efct_lio_check_demo_mode_login_only(struct se_portal_group *stpg)
101662306a36Sopenharmony_ci{
101762306a36Sopenharmony_ci	struct efct_lio_tpg *tpg = container_of(stpg, struct efct_lio_tpg, tpg);
101862306a36Sopenharmony_ci
101962306a36Sopenharmony_ci	return tpg->tpg_attrib.demo_mode_login_only;
102062306a36Sopenharmony_ci}
102162306a36Sopenharmony_ci
102262306a36Sopenharmony_cistatic int
102362306a36Sopenharmony_ciefct_lio_npiv_check_demo_mode_login_only(struct se_portal_group *stpg)
102462306a36Sopenharmony_ci{
102562306a36Sopenharmony_ci	struct efct_lio_tpg *tpg = container_of(stpg, struct efct_lio_tpg, tpg);
102662306a36Sopenharmony_ci
102762306a36Sopenharmony_ci	return tpg->tpg_attrib.demo_mode_login_only;
102862306a36Sopenharmony_ci}
102962306a36Sopenharmony_ci
103062306a36Sopenharmony_cistatic struct efct_lio_tpg *
103162306a36Sopenharmony_ciefct_get_vport_tpg(struct efc_node *node)
103262306a36Sopenharmony_ci{
103362306a36Sopenharmony_ci	struct efct *efct;
103462306a36Sopenharmony_ci	u64 wwpn = node->nport->wwpn;
103562306a36Sopenharmony_ci	struct efct_lio_vport_list_t *vport, *next;
103662306a36Sopenharmony_ci	struct efct_lio_vport *lio_vport = NULL;
103762306a36Sopenharmony_ci	struct efct_lio_tpg *tpg = NULL;
103862306a36Sopenharmony_ci	unsigned long flags = 0;
103962306a36Sopenharmony_ci
104062306a36Sopenharmony_ci	efct = node->efc->base;
104162306a36Sopenharmony_ci	spin_lock_irqsave(&efct->tgt_efct.efct_lio_lock, flags);
104262306a36Sopenharmony_ci	list_for_each_entry_safe(vport, next, &efct->tgt_efct.vport_list,
104362306a36Sopenharmony_ci				 list_entry) {
104462306a36Sopenharmony_ci		lio_vport = vport->lio_vport;
104562306a36Sopenharmony_ci		if (wwpn && lio_vport && lio_vport->npiv_wwpn == wwpn) {
104662306a36Sopenharmony_ci			efc_log_debug(efct, "found tpg on vport\n");
104762306a36Sopenharmony_ci			tpg = lio_vport->tpg;
104862306a36Sopenharmony_ci			break;
104962306a36Sopenharmony_ci		}
105062306a36Sopenharmony_ci	}
105162306a36Sopenharmony_ci	spin_unlock_irqrestore(&efct->tgt_efct.efct_lio_lock, flags);
105262306a36Sopenharmony_ci	return tpg;
105362306a36Sopenharmony_ci}
105462306a36Sopenharmony_ci
105562306a36Sopenharmony_cistatic void
105662306a36Sopenharmony_ci_efct_tgt_node_free(struct kref *arg)
105762306a36Sopenharmony_ci{
105862306a36Sopenharmony_ci	struct efct_node *tgt_node = container_of(arg, struct efct_node, ref);
105962306a36Sopenharmony_ci	struct efc_node *node = tgt_node->node;
106062306a36Sopenharmony_ci
106162306a36Sopenharmony_ci	efc_scsi_del_initiator_complete(node->efc, node);
106262306a36Sopenharmony_ci	kfree(tgt_node);
106362306a36Sopenharmony_ci}
106462306a36Sopenharmony_ci
106562306a36Sopenharmony_cistatic int efct_session_cb(struct se_portal_group *se_tpg,
106662306a36Sopenharmony_ci			   struct se_session *se_sess, void *private)
106762306a36Sopenharmony_ci{
106862306a36Sopenharmony_ci	struct efc_node *node = private;
106962306a36Sopenharmony_ci	struct efct_node *tgt_node;
107062306a36Sopenharmony_ci	struct efct *efct = node->efc->base;
107162306a36Sopenharmony_ci
107262306a36Sopenharmony_ci	tgt_node = kzalloc(sizeof(*tgt_node), GFP_KERNEL);
107362306a36Sopenharmony_ci	if (!tgt_node)
107462306a36Sopenharmony_ci		return -ENOMEM;
107562306a36Sopenharmony_ci
107662306a36Sopenharmony_ci	kref_init(&tgt_node->ref);
107762306a36Sopenharmony_ci	tgt_node->release = _efct_tgt_node_free;
107862306a36Sopenharmony_ci
107962306a36Sopenharmony_ci	tgt_node->session = se_sess;
108062306a36Sopenharmony_ci	node->tgt_node = tgt_node;
108162306a36Sopenharmony_ci	tgt_node->efct = efct;
108262306a36Sopenharmony_ci
108362306a36Sopenharmony_ci	tgt_node->node = node;
108462306a36Sopenharmony_ci
108562306a36Sopenharmony_ci	tgt_node->node_fc_id = node->rnode.fc_id;
108662306a36Sopenharmony_ci	tgt_node->port_fc_id = node->nport->fc_id;
108762306a36Sopenharmony_ci	tgt_node->vpi = node->nport->indicator;
108862306a36Sopenharmony_ci	tgt_node->rpi = node->rnode.indicator;
108962306a36Sopenharmony_ci
109062306a36Sopenharmony_ci	spin_lock_init(&tgt_node->active_ios_lock);
109162306a36Sopenharmony_ci	INIT_LIST_HEAD(&tgt_node->active_ios);
109262306a36Sopenharmony_ci
109362306a36Sopenharmony_ci	return 0;
109462306a36Sopenharmony_ci}
109562306a36Sopenharmony_ci
109662306a36Sopenharmony_ciint efct_scsi_tgt_new_device(struct efct *efct)
109762306a36Sopenharmony_ci{
109862306a36Sopenharmony_ci	u32 total_ios;
109962306a36Sopenharmony_ci
110062306a36Sopenharmony_ci	/* Get the max settings */
110162306a36Sopenharmony_ci	efct->tgt_efct.max_sge = sli_get_max_sge(&efct->hw.sli);
110262306a36Sopenharmony_ci	efct->tgt_efct.max_sgl = sli_get_max_sgl(&efct->hw.sli);
110362306a36Sopenharmony_ci
110462306a36Sopenharmony_ci	/* initialize IO watermark fields */
110562306a36Sopenharmony_ci	atomic_set(&efct->tgt_efct.ios_in_use, 0);
110662306a36Sopenharmony_ci	total_ios = efct->hw.config.n_io;
110762306a36Sopenharmony_ci	efc_log_debug(efct, "total_ios=%d\n", total_ios);
110862306a36Sopenharmony_ci	efct->tgt_efct.watermark_min =
110962306a36Sopenharmony_ci			(total_ios * EFCT_WATERMARK_LOW_PCT) / 100;
111062306a36Sopenharmony_ci	efct->tgt_efct.watermark_max =
111162306a36Sopenharmony_ci			(total_ios * EFCT_WATERMARK_HIGH_PCT) / 100;
111262306a36Sopenharmony_ci	atomic_set(&efct->tgt_efct.io_high_watermark,
111362306a36Sopenharmony_ci		   efct->tgt_efct.watermark_max);
111462306a36Sopenharmony_ci	atomic_set(&efct->tgt_efct.watermark_hit, 0);
111562306a36Sopenharmony_ci	atomic_set(&efct->tgt_efct.initiator_count, 0);
111662306a36Sopenharmony_ci
111762306a36Sopenharmony_ci	lio_wq = create_singlethread_workqueue("efct_lio_worker");
111862306a36Sopenharmony_ci	if (!lio_wq) {
111962306a36Sopenharmony_ci		efc_log_err(efct, "workqueue create failed\n");
112062306a36Sopenharmony_ci		return -EIO;
112162306a36Sopenharmony_ci	}
112262306a36Sopenharmony_ci
112362306a36Sopenharmony_ci	spin_lock_init(&efct->tgt_efct.efct_lio_lock);
112462306a36Sopenharmony_ci	INIT_LIST_HEAD(&efct->tgt_efct.vport_list);
112562306a36Sopenharmony_ci
112662306a36Sopenharmony_ci	return 0;
112762306a36Sopenharmony_ci}
112862306a36Sopenharmony_ci
112962306a36Sopenharmony_ciint efct_scsi_tgt_del_device(struct efct *efct)
113062306a36Sopenharmony_ci{
113162306a36Sopenharmony_ci	flush_workqueue(lio_wq);
113262306a36Sopenharmony_ci
113362306a36Sopenharmony_ci	return 0;
113462306a36Sopenharmony_ci}
113562306a36Sopenharmony_ci
113662306a36Sopenharmony_ciint
113762306a36Sopenharmony_ciefct_scsi_tgt_new_nport(struct efc *efc, struct efc_nport *nport)
113862306a36Sopenharmony_ci{
113962306a36Sopenharmony_ci	struct efct *efct = nport->efc->base;
114062306a36Sopenharmony_ci
114162306a36Sopenharmony_ci	efc_log_debug(efct, "New SPORT: %s bound to %s\n", nport->display_name,
114262306a36Sopenharmony_ci		       efct->tgt_efct.lio_nport->wwpn_str);
114362306a36Sopenharmony_ci
114462306a36Sopenharmony_ci	return 0;
114562306a36Sopenharmony_ci}
114662306a36Sopenharmony_ci
114762306a36Sopenharmony_civoid
114862306a36Sopenharmony_ciefct_scsi_tgt_del_nport(struct efc *efc, struct efc_nport *nport)
114962306a36Sopenharmony_ci{
115062306a36Sopenharmony_ci	efc_log_debug(efc, "Del SPORT: %s\n", nport->display_name);
115162306a36Sopenharmony_ci}
115262306a36Sopenharmony_ci
115362306a36Sopenharmony_cistatic void efct_lio_setup_session(struct work_struct *work)
115462306a36Sopenharmony_ci{
115562306a36Sopenharmony_ci	struct efct_lio_wq_data *wq_data =
115662306a36Sopenharmony_ci		container_of(work, struct efct_lio_wq_data, work);
115762306a36Sopenharmony_ci	struct efct *efct = wq_data->efct;
115862306a36Sopenharmony_ci	struct efc_node *node = wq_data->ptr;
115962306a36Sopenharmony_ci	char wwpn[WWN_NAME_LEN];
116062306a36Sopenharmony_ci	struct efct_lio_tpg *tpg;
116162306a36Sopenharmony_ci	struct efct_node *tgt_node;
116262306a36Sopenharmony_ci	struct se_portal_group *se_tpg;
116362306a36Sopenharmony_ci	struct se_session *se_sess;
116462306a36Sopenharmony_ci	int watermark;
116562306a36Sopenharmony_ci	int ini_count;
116662306a36Sopenharmony_ci	u64 id;
116762306a36Sopenharmony_ci
116862306a36Sopenharmony_ci	/* Check to see if it's belongs to vport,
116962306a36Sopenharmony_ci	 * if not get physical port
117062306a36Sopenharmony_ci	 */
117162306a36Sopenharmony_ci	tpg = efct_get_vport_tpg(node);
117262306a36Sopenharmony_ci	if (tpg) {
117362306a36Sopenharmony_ci		se_tpg = &tpg->tpg;
117462306a36Sopenharmony_ci	} else if (efct->tgt_efct.tpg) {
117562306a36Sopenharmony_ci		tpg = efct->tgt_efct.tpg;
117662306a36Sopenharmony_ci		se_tpg = &tpg->tpg;
117762306a36Sopenharmony_ci	} else {
117862306a36Sopenharmony_ci		efc_log_err(efct, "failed to init session\n");
117962306a36Sopenharmony_ci		return;
118062306a36Sopenharmony_ci	}
118162306a36Sopenharmony_ci
118262306a36Sopenharmony_ci	/*
118362306a36Sopenharmony_ci	 * Format the FCP Initiator port_name into colon
118462306a36Sopenharmony_ci	 * separated values to match the format by our explicit
118562306a36Sopenharmony_ci	 * ConfigFS NodeACLs.
118662306a36Sopenharmony_ci	 */
118762306a36Sopenharmony_ci	efct_format_wwn(wwpn, sizeof(wwpn), "",	efc_node_get_wwpn(node));
118862306a36Sopenharmony_ci
118962306a36Sopenharmony_ci	se_sess = target_setup_session(se_tpg, 0, 0, TARGET_PROT_NORMAL, wwpn,
119062306a36Sopenharmony_ci				       node, efct_session_cb);
119162306a36Sopenharmony_ci	if (IS_ERR(se_sess)) {
119262306a36Sopenharmony_ci		efc_log_err(efct, "failed to setup session\n");
119362306a36Sopenharmony_ci		kfree(wq_data);
119462306a36Sopenharmony_ci		efc_scsi_sess_reg_complete(node, -EIO);
119562306a36Sopenharmony_ci		return;
119662306a36Sopenharmony_ci	}
119762306a36Sopenharmony_ci
119862306a36Sopenharmony_ci	tgt_node = node->tgt_node;
119962306a36Sopenharmony_ci	id = (u64) tgt_node->port_fc_id << 32 | tgt_node->node_fc_id;
120062306a36Sopenharmony_ci
120162306a36Sopenharmony_ci	efc_log_debug(efct, "new initiator sess=%p node=%p id: %llx\n",
120262306a36Sopenharmony_ci		      se_sess, node, id);
120362306a36Sopenharmony_ci
120462306a36Sopenharmony_ci	if (xa_err(xa_store(&efct->lookup, id, tgt_node, GFP_KERNEL)))
120562306a36Sopenharmony_ci		efc_log_err(efct, "Node lookup store failed\n");
120662306a36Sopenharmony_ci
120762306a36Sopenharmony_ci	efc_scsi_sess_reg_complete(node, 0);
120862306a36Sopenharmony_ci
120962306a36Sopenharmony_ci	/* update IO watermark: increment initiator count */
121062306a36Sopenharmony_ci	ini_count = atomic_add_return(1, &efct->tgt_efct.initiator_count);
121162306a36Sopenharmony_ci	watermark = efct->tgt_efct.watermark_max -
121262306a36Sopenharmony_ci		    ini_count * EFCT_IO_WATERMARK_PER_INITIATOR;
121362306a36Sopenharmony_ci	watermark = (efct->tgt_efct.watermark_min > watermark) ?
121462306a36Sopenharmony_ci			efct->tgt_efct.watermark_min : watermark;
121562306a36Sopenharmony_ci	atomic_set(&efct->tgt_efct.io_high_watermark, watermark);
121662306a36Sopenharmony_ci
121762306a36Sopenharmony_ci	kfree(wq_data);
121862306a36Sopenharmony_ci}
121962306a36Sopenharmony_ci
122062306a36Sopenharmony_ciint efct_scsi_new_initiator(struct efc *efc, struct efc_node *node)
122162306a36Sopenharmony_ci{
122262306a36Sopenharmony_ci	struct efct *efct = node->efc->base;
122362306a36Sopenharmony_ci	struct efct_lio_wq_data *wq_data;
122462306a36Sopenharmony_ci
122562306a36Sopenharmony_ci	/*
122662306a36Sopenharmony_ci	 * Since LIO only supports initiator validation at thread level,
122762306a36Sopenharmony_ci	 * we are open minded and accept all callers.
122862306a36Sopenharmony_ci	 */
122962306a36Sopenharmony_ci	wq_data = kzalloc(sizeof(*wq_data), GFP_ATOMIC);
123062306a36Sopenharmony_ci	if (!wq_data)
123162306a36Sopenharmony_ci		return -ENOMEM;
123262306a36Sopenharmony_ci
123362306a36Sopenharmony_ci	wq_data->ptr = node;
123462306a36Sopenharmony_ci	wq_data->efct = efct;
123562306a36Sopenharmony_ci	INIT_WORK(&wq_data->work, efct_lio_setup_session);
123662306a36Sopenharmony_ci	queue_work(lio_wq, &wq_data->work);
123762306a36Sopenharmony_ci	return EFC_SCSI_CALL_ASYNC;
123862306a36Sopenharmony_ci}
123962306a36Sopenharmony_ci
124062306a36Sopenharmony_cistatic void efct_lio_remove_session(struct work_struct *work)
124162306a36Sopenharmony_ci{
124262306a36Sopenharmony_ci	struct efct_lio_wq_data *wq_data =
124362306a36Sopenharmony_ci		container_of(work, struct efct_lio_wq_data, work);
124462306a36Sopenharmony_ci	struct efct *efct = wq_data->efct;
124562306a36Sopenharmony_ci	struct efc_node *node = wq_data->ptr;
124662306a36Sopenharmony_ci	struct efct_node *tgt_node;
124762306a36Sopenharmony_ci	struct se_session *se_sess;
124862306a36Sopenharmony_ci
124962306a36Sopenharmony_ci	tgt_node = node->tgt_node;
125062306a36Sopenharmony_ci	if (!tgt_node) {
125162306a36Sopenharmony_ci		/* base driver has sent back-to-back requests
125262306a36Sopenharmony_ci		 * to unreg session with no intervening
125362306a36Sopenharmony_ci		 * register
125462306a36Sopenharmony_ci		 */
125562306a36Sopenharmony_ci		efc_log_err(efct, "unreg session for NULL session\n");
125662306a36Sopenharmony_ci		efc_scsi_del_initiator_complete(node->efc, node);
125762306a36Sopenharmony_ci		return;
125862306a36Sopenharmony_ci	}
125962306a36Sopenharmony_ci
126062306a36Sopenharmony_ci	se_sess = tgt_node->session;
126162306a36Sopenharmony_ci	efc_log_debug(efct, "unreg session se_sess=%p node=%p\n",
126262306a36Sopenharmony_ci		       se_sess, node);
126362306a36Sopenharmony_ci
126462306a36Sopenharmony_ci	/* first flag all session commands to complete */
126562306a36Sopenharmony_ci	target_stop_session(se_sess);
126662306a36Sopenharmony_ci
126762306a36Sopenharmony_ci	/* now wait for session commands to complete */
126862306a36Sopenharmony_ci	target_wait_for_sess_cmds(se_sess);
126962306a36Sopenharmony_ci	target_remove_session(se_sess);
127062306a36Sopenharmony_ci	tgt_node->session = NULL;
127162306a36Sopenharmony_ci	node->tgt_node = NULL;
127262306a36Sopenharmony_ci	kref_put(&tgt_node->ref, tgt_node->release);
127362306a36Sopenharmony_ci
127462306a36Sopenharmony_ci	kfree(wq_data);
127562306a36Sopenharmony_ci}
127662306a36Sopenharmony_ci
127762306a36Sopenharmony_ciint efct_scsi_del_initiator(struct efc *efc, struct efc_node *node, int reason)
127862306a36Sopenharmony_ci{
127962306a36Sopenharmony_ci	struct efct *efct = node->efc->base;
128062306a36Sopenharmony_ci	struct efct_node *tgt_node = node->tgt_node;
128162306a36Sopenharmony_ci	struct efct_lio_wq_data *wq_data;
128262306a36Sopenharmony_ci	int watermark;
128362306a36Sopenharmony_ci	int ini_count;
128462306a36Sopenharmony_ci	u64 id;
128562306a36Sopenharmony_ci
128662306a36Sopenharmony_ci	if (reason == EFCT_SCSI_INITIATOR_MISSING)
128762306a36Sopenharmony_ci		return EFC_SCSI_CALL_COMPLETE;
128862306a36Sopenharmony_ci
128962306a36Sopenharmony_ci	if (!tgt_node) {
129062306a36Sopenharmony_ci		efc_log_err(efct, "tgt_node is NULL\n");
129162306a36Sopenharmony_ci		return -EIO;
129262306a36Sopenharmony_ci	}
129362306a36Sopenharmony_ci
129462306a36Sopenharmony_ci	wq_data = kzalloc(sizeof(*wq_data), GFP_ATOMIC);
129562306a36Sopenharmony_ci	if (!wq_data)
129662306a36Sopenharmony_ci		return -ENOMEM;
129762306a36Sopenharmony_ci
129862306a36Sopenharmony_ci	id = (u64) tgt_node->port_fc_id << 32 | tgt_node->node_fc_id;
129962306a36Sopenharmony_ci	xa_erase(&efct->lookup, id);
130062306a36Sopenharmony_ci
130162306a36Sopenharmony_ci	wq_data->ptr = node;
130262306a36Sopenharmony_ci	wq_data->efct = efct;
130362306a36Sopenharmony_ci	INIT_WORK(&wq_data->work, efct_lio_remove_session);
130462306a36Sopenharmony_ci	queue_work(lio_wq, &wq_data->work);
130562306a36Sopenharmony_ci
130662306a36Sopenharmony_ci	/*
130762306a36Sopenharmony_ci	 * update IO watermark: decrement initiator count
130862306a36Sopenharmony_ci	 */
130962306a36Sopenharmony_ci	ini_count = atomic_sub_return(1, &efct->tgt_efct.initiator_count);
131062306a36Sopenharmony_ci
131162306a36Sopenharmony_ci	watermark = efct->tgt_efct.watermark_max -
131262306a36Sopenharmony_ci		    ini_count * EFCT_IO_WATERMARK_PER_INITIATOR;
131362306a36Sopenharmony_ci	watermark = (efct->tgt_efct.watermark_min > watermark) ?
131462306a36Sopenharmony_ci			efct->tgt_efct.watermark_min : watermark;
131562306a36Sopenharmony_ci	atomic_set(&efct->tgt_efct.io_high_watermark, watermark);
131662306a36Sopenharmony_ci
131762306a36Sopenharmony_ci	return EFC_SCSI_CALL_ASYNC;
131862306a36Sopenharmony_ci}
131962306a36Sopenharmony_ci
132062306a36Sopenharmony_civoid efct_scsi_recv_cmd(struct efct_io *io, uint64_t lun, u8 *cdb,
132162306a36Sopenharmony_ci		       u32 cdb_len, u32 flags)
132262306a36Sopenharmony_ci{
132362306a36Sopenharmony_ci	struct efct_scsi_tgt_io *ocp = &io->tgt_io;
132462306a36Sopenharmony_ci	struct se_cmd *se_cmd = &io->tgt_io.cmd;
132562306a36Sopenharmony_ci	struct efct *efct = io->efct;
132662306a36Sopenharmony_ci	char *ddir;
132762306a36Sopenharmony_ci	struct efct_node *tgt_node;
132862306a36Sopenharmony_ci	struct se_session *se_sess;
132962306a36Sopenharmony_ci	int rc = 0;
133062306a36Sopenharmony_ci
133162306a36Sopenharmony_ci	memset(ocp, 0, sizeof(struct efct_scsi_tgt_io));
133262306a36Sopenharmony_ci	efct_set_lio_io_state(io, EFCT_LIO_STATE_SCSI_RECV_CMD);
133362306a36Sopenharmony_ci	atomic_add_return(1, &efct->tgt_efct.ios_in_use);
133462306a36Sopenharmony_ci
133562306a36Sopenharmony_ci	/* set target timeout */
133662306a36Sopenharmony_ci	io->timeout = efct->target_io_timer_sec;
133762306a36Sopenharmony_ci
133862306a36Sopenharmony_ci	if (flags & EFCT_SCSI_CMD_SIMPLE)
133962306a36Sopenharmony_ci		ocp->task_attr = TCM_SIMPLE_TAG;
134062306a36Sopenharmony_ci	else if (flags & EFCT_SCSI_CMD_HEAD_OF_QUEUE)
134162306a36Sopenharmony_ci		ocp->task_attr = TCM_HEAD_TAG;
134262306a36Sopenharmony_ci	else if (flags & EFCT_SCSI_CMD_ORDERED)
134362306a36Sopenharmony_ci		ocp->task_attr = TCM_ORDERED_TAG;
134462306a36Sopenharmony_ci	else if (flags & EFCT_SCSI_CMD_ACA)
134562306a36Sopenharmony_ci		ocp->task_attr = TCM_ACA_TAG;
134662306a36Sopenharmony_ci
134762306a36Sopenharmony_ci	switch (flags & (EFCT_SCSI_CMD_DIR_IN | EFCT_SCSI_CMD_DIR_OUT)) {
134862306a36Sopenharmony_ci	case EFCT_SCSI_CMD_DIR_IN:
134962306a36Sopenharmony_ci		ddir = "FROM_INITIATOR";
135062306a36Sopenharmony_ci		ocp->ddir = DMA_TO_DEVICE;
135162306a36Sopenharmony_ci		break;
135262306a36Sopenharmony_ci	case EFCT_SCSI_CMD_DIR_OUT:
135362306a36Sopenharmony_ci		ddir = "TO_INITIATOR";
135462306a36Sopenharmony_ci		ocp->ddir = DMA_FROM_DEVICE;
135562306a36Sopenharmony_ci		break;
135662306a36Sopenharmony_ci	case EFCT_SCSI_CMD_DIR_IN | EFCT_SCSI_CMD_DIR_OUT:
135762306a36Sopenharmony_ci		ddir = "BIDIR";
135862306a36Sopenharmony_ci		ocp->ddir = DMA_BIDIRECTIONAL;
135962306a36Sopenharmony_ci		break;
136062306a36Sopenharmony_ci	default:
136162306a36Sopenharmony_ci		ddir = "NONE";
136262306a36Sopenharmony_ci		ocp->ddir = DMA_NONE;
136362306a36Sopenharmony_ci		break;
136462306a36Sopenharmony_ci	}
136562306a36Sopenharmony_ci
136662306a36Sopenharmony_ci	ocp->lun = lun;
136762306a36Sopenharmony_ci	efct_lio_io_printf(io, "new cmd=0x%x ddir=%s dl=%u\n",
136862306a36Sopenharmony_ci			   cdb[0], ddir, io->exp_xfer_len);
136962306a36Sopenharmony_ci
137062306a36Sopenharmony_ci	tgt_node = io->node;
137162306a36Sopenharmony_ci	se_sess = tgt_node->session;
137262306a36Sopenharmony_ci	if (!se_sess) {
137362306a36Sopenharmony_ci		efc_log_err(efct, "No session found to submit IO se_cmd: %p\n",
137462306a36Sopenharmony_ci			    &ocp->cmd);
137562306a36Sopenharmony_ci		efct_scsi_io_free(io);
137662306a36Sopenharmony_ci		return;
137762306a36Sopenharmony_ci	}
137862306a36Sopenharmony_ci
137962306a36Sopenharmony_ci	efct_set_lio_io_state(io, EFCT_LIO_STATE_TGT_SUBMIT_CMD);
138062306a36Sopenharmony_ci	rc = target_init_cmd(se_cmd, se_sess, &io->tgt_io.sense_buffer[0],
138162306a36Sopenharmony_ci			     ocp->lun, io->exp_xfer_len, ocp->task_attr,
138262306a36Sopenharmony_ci			     ocp->ddir, TARGET_SCF_ACK_KREF);
138362306a36Sopenharmony_ci	if (rc) {
138462306a36Sopenharmony_ci		efc_log_err(efct, "failed to init cmd se_cmd: %p\n", se_cmd);
138562306a36Sopenharmony_ci		efct_scsi_io_free(io);
138662306a36Sopenharmony_ci		return;
138762306a36Sopenharmony_ci	}
138862306a36Sopenharmony_ci
138962306a36Sopenharmony_ci	if (target_submit_prep(se_cmd, cdb, NULL, 0, NULL, 0,
139062306a36Sopenharmony_ci				NULL, 0, GFP_ATOMIC))
139162306a36Sopenharmony_ci		return;
139262306a36Sopenharmony_ci
139362306a36Sopenharmony_ci	target_submit(se_cmd);
139462306a36Sopenharmony_ci}
139562306a36Sopenharmony_ci
139662306a36Sopenharmony_ciint
139762306a36Sopenharmony_ciefct_scsi_recv_tmf(struct efct_io *tmfio, u32 lun, enum efct_scsi_tmf_cmd cmd,
139862306a36Sopenharmony_ci		   struct efct_io *io_to_abort, u32 flags)
139962306a36Sopenharmony_ci{
140062306a36Sopenharmony_ci	unsigned char tmr_func;
140162306a36Sopenharmony_ci	struct efct *efct = tmfio->efct;
140262306a36Sopenharmony_ci	struct efct_scsi_tgt_io *ocp = &tmfio->tgt_io;
140362306a36Sopenharmony_ci	struct efct_node *tgt_node;
140462306a36Sopenharmony_ci	struct se_session *se_sess;
140562306a36Sopenharmony_ci	int rc;
140662306a36Sopenharmony_ci
140762306a36Sopenharmony_ci	memset(ocp, 0, sizeof(struct efct_scsi_tgt_io));
140862306a36Sopenharmony_ci	efct_set_lio_io_state(tmfio, EFCT_LIO_STATE_SCSI_RECV_TMF);
140962306a36Sopenharmony_ci	atomic_add_return(1, &efct->tgt_efct.ios_in_use);
141062306a36Sopenharmony_ci	efct_lio_tmfio_printf(tmfio, "%s: new tmf %x lun=%u\n",
141162306a36Sopenharmony_ci			      tmfio->display_name, cmd, lun);
141262306a36Sopenharmony_ci
141362306a36Sopenharmony_ci	switch (cmd) {
141462306a36Sopenharmony_ci	case EFCT_SCSI_TMF_ABORT_TASK:
141562306a36Sopenharmony_ci		tmr_func = TMR_ABORT_TASK;
141662306a36Sopenharmony_ci		break;
141762306a36Sopenharmony_ci	case EFCT_SCSI_TMF_ABORT_TASK_SET:
141862306a36Sopenharmony_ci		tmr_func = TMR_ABORT_TASK_SET;
141962306a36Sopenharmony_ci		break;
142062306a36Sopenharmony_ci	case EFCT_SCSI_TMF_CLEAR_TASK_SET:
142162306a36Sopenharmony_ci		tmr_func = TMR_CLEAR_TASK_SET;
142262306a36Sopenharmony_ci		break;
142362306a36Sopenharmony_ci	case EFCT_SCSI_TMF_LOGICAL_UNIT_RESET:
142462306a36Sopenharmony_ci		tmr_func = TMR_LUN_RESET;
142562306a36Sopenharmony_ci		break;
142662306a36Sopenharmony_ci	case EFCT_SCSI_TMF_CLEAR_ACA:
142762306a36Sopenharmony_ci		tmr_func = TMR_CLEAR_ACA;
142862306a36Sopenharmony_ci		break;
142962306a36Sopenharmony_ci	case EFCT_SCSI_TMF_TARGET_RESET:
143062306a36Sopenharmony_ci		tmr_func = TMR_TARGET_WARM_RESET;
143162306a36Sopenharmony_ci		break;
143262306a36Sopenharmony_ci	case EFCT_SCSI_TMF_QUERY_ASYNCHRONOUS_EVENT:
143362306a36Sopenharmony_ci	case EFCT_SCSI_TMF_QUERY_TASK_SET:
143462306a36Sopenharmony_ci	default:
143562306a36Sopenharmony_ci		goto tmf_fail;
143662306a36Sopenharmony_ci	}
143762306a36Sopenharmony_ci
143862306a36Sopenharmony_ci	tmfio->tgt_io.tmf = tmr_func;
143962306a36Sopenharmony_ci	tmfio->tgt_io.lun = lun;
144062306a36Sopenharmony_ci	tmfio->tgt_io.io_to_abort = io_to_abort;
144162306a36Sopenharmony_ci
144262306a36Sopenharmony_ci	tgt_node = tmfio->node;
144362306a36Sopenharmony_ci
144462306a36Sopenharmony_ci	se_sess = tgt_node->session;
144562306a36Sopenharmony_ci	if (!se_sess)
144662306a36Sopenharmony_ci		return 0;
144762306a36Sopenharmony_ci
144862306a36Sopenharmony_ci	rc = target_submit_tmr(&ocp->cmd, se_sess, NULL, lun, ocp, tmr_func,
144962306a36Sopenharmony_ci			GFP_ATOMIC, tmfio->init_task_tag, TARGET_SCF_ACK_KREF);
145062306a36Sopenharmony_ci
145162306a36Sopenharmony_ci	efct_set_lio_io_state(tmfio, EFCT_LIO_STATE_TGT_SUBMIT_TMR);
145262306a36Sopenharmony_ci	if (rc)
145362306a36Sopenharmony_ci		goto tmf_fail;
145462306a36Sopenharmony_ci
145562306a36Sopenharmony_ci	return 0;
145662306a36Sopenharmony_ci
145762306a36Sopenharmony_citmf_fail:
145862306a36Sopenharmony_ci	efct_scsi_send_tmf_resp(tmfio, EFCT_SCSI_TMF_FUNCTION_REJECTED,
145962306a36Sopenharmony_ci				NULL, efct_lio_null_tmf_done, NULL);
146062306a36Sopenharmony_ci	return 0;
146162306a36Sopenharmony_ci}
146262306a36Sopenharmony_ci
146362306a36Sopenharmony_ci/* Start items for efct_lio_tpg_attrib_cit */
146462306a36Sopenharmony_ci
146562306a36Sopenharmony_ci#define DEF_EFCT_TPG_ATTRIB(name)					  \
146662306a36Sopenharmony_ci									  \
146762306a36Sopenharmony_cistatic ssize_t efct_lio_tpg_attrib_##name##_show(			  \
146862306a36Sopenharmony_ci		struct config_item *item, char *page)			  \
146962306a36Sopenharmony_ci{									  \
147062306a36Sopenharmony_ci	struct se_portal_group *se_tpg = to_tpg(item);			  \
147162306a36Sopenharmony_ci	struct efct_lio_tpg *tpg = container_of(se_tpg,			  \
147262306a36Sopenharmony_ci			struct efct_lio_tpg, tpg);			  \
147362306a36Sopenharmony_ci									  \
147462306a36Sopenharmony_ci	return sprintf(page, "%u\n", tpg->tpg_attrib.name);		  \
147562306a36Sopenharmony_ci}									  \
147662306a36Sopenharmony_ci									  \
147762306a36Sopenharmony_cistatic ssize_t efct_lio_tpg_attrib_##name##_store(			  \
147862306a36Sopenharmony_ci		struct config_item *item, const char *page, size_t count) \
147962306a36Sopenharmony_ci{									  \
148062306a36Sopenharmony_ci	struct se_portal_group *se_tpg = to_tpg(item);			  \
148162306a36Sopenharmony_ci	struct efct_lio_tpg *tpg = container_of(se_tpg,			  \
148262306a36Sopenharmony_ci					struct efct_lio_tpg, tpg);	  \
148362306a36Sopenharmony_ci	struct efct_lio_tpg_attrib *a = &tpg->tpg_attrib;		  \
148462306a36Sopenharmony_ci	unsigned long val;						  \
148562306a36Sopenharmony_ci	int ret;							  \
148662306a36Sopenharmony_ci									  \
148762306a36Sopenharmony_ci	ret = kstrtoul(page, 0, &val);					  \
148862306a36Sopenharmony_ci	if (ret < 0) {							  \
148962306a36Sopenharmony_ci		pr_err("kstrtoul() failed with ret: %d\n", ret);	  \
149062306a36Sopenharmony_ci		return ret;						  \
149162306a36Sopenharmony_ci	}								  \
149262306a36Sopenharmony_ci									  \
149362306a36Sopenharmony_ci	if (val != 0 && val != 1) {					  \
149462306a36Sopenharmony_ci		pr_err("Illegal boolean value %lu\n", val);		  \
149562306a36Sopenharmony_ci		return -EINVAL;						  \
149662306a36Sopenharmony_ci	}								  \
149762306a36Sopenharmony_ci									  \
149862306a36Sopenharmony_ci	a->name = val;							  \
149962306a36Sopenharmony_ci									  \
150062306a36Sopenharmony_ci	return count;							  \
150162306a36Sopenharmony_ci}									  \
150262306a36Sopenharmony_ciCONFIGFS_ATTR(efct_lio_tpg_attrib_, name)
150362306a36Sopenharmony_ci
150462306a36Sopenharmony_ciDEF_EFCT_TPG_ATTRIB(generate_node_acls);
150562306a36Sopenharmony_ciDEF_EFCT_TPG_ATTRIB(cache_dynamic_acls);
150662306a36Sopenharmony_ciDEF_EFCT_TPG_ATTRIB(demo_mode_write_protect);
150762306a36Sopenharmony_ciDEF_EFCT_TPG_ATTRIB(prod_mode_write_protect);
150862306a36Sopenharmony_ciDEF_EFCT_TPG_ATTRIB(demo_mode_login_only);
150962306a36Sopenharmony_ciDEF_EFCT_TPG_ATTRIB(session_deletion_wait);
151062306a36Sopenharmony_ci
151162306a36Sopenharmony_cistatic struct configfs_attribute *efct_lio_tpg_attrib_attrs[] = {
151262306a36Sopenharmony_ci	&efct_lio_tpg_attrib_attr_generate_node_acls,
151362306a36Sopenharmony_ci	&efct_lio_tpg_attrib_attr_cache_dynamic_acls,
151462306a36Sopenharmony_ci	&efct_lio_tpg_attrib_attr_demo_mode_write_protect,
151562306a36Sopenharmony_ci	&efct_lio_tpg_attrib_attr_prod_mode_write_protect,
151662306a36Sopenharmony_ci	&efct_lio_tpg_attrib_attr_demo_mode_login_only,
151762306a36Sopenharmony_ci	&efct_lio_tpg_attrib_attr_session_deletion_wait,
151862306a36Sopenharmony_ci	NULL,
151962306a36Sopenharmony_ci};
152062306a36Sopenharmony_ci
152162306a36Sopenharmony_ci#define DEF_EFCT_NPIV_TPG_ATTRIB(name)					   \
152262306a36Sopenharmony_ci									   \
152362306a36Sopenharmony_cistatic ssize_t efct_lio_npiv_tpg_attrib_##name##_show(			   \
152462306a36Sopenharmony_ci		struct config_item *item, char *page)			   \
152562306a36Sopenharmony_ci{									   \
152662306a36Sopenharmony_ci	struct se_portal_group *se_tpg = to_tpg(item);			   \
152762306a36Sopenharmony_ci	struct efct_lio_tpg *tpg = container_of(se_tpg,			   \
152862306a36Sopenharmony_ci			struct efct_lio_tpg, tpg);			   \
152962306a36Sopenharmony_ci									   \
153062306a36Sopenharmony_ci	return sprintf(page, "%u\n", tpg->tpg_attrib.name);		   \
153162306a36Sopenharmony_ci}									   \
153262306a36Sopenharmony_ci									   \
153362306a36Sopenharmony_cistatic ssize_t efct_lio_npiv_tpg_attrib_##name##_store(			   \
153462306a36Sopenharmony_ci		struct config_item *item, const char *page, size_t count)  \
153562306a36Sopenharmony_ci{									   \
153662306a36Sopenharmony_ci	struct se_portal_group *se_tpg = to_tpg(item);			   \
153762306a36Sopenharmony_ci	struct efct_lio_tpg *tpg = container_of(se_tpg,			   \
153862306a36Sopenharmony_ci			struct efct_lio_tpg, tpg);			   \
153962306a36Sopenharmony_ci	struct efct_lio_tpg_attrib *a = &tpg->tpg_attrib;		   \
154062306a36Sopenharmony_ci	unsigned long val;						   \
154162306a36Sopenharmony_ci	int ret;							   \
154262306a36Sopenharmony_ci									   \
154362306a36Sopenharmony_ci	ret = kstrtoul(page, 0, &val);					   \
154462306a36Sopenharmony_ci	if (ret < 0) {							   \
154562306a36Sopenharmony_ci		pr_err("kstrtoul() failed with ret: %d\n", ret);	   \
154662306a36Sopenharmony_ci		return ret;						   \
154762306a36Sopenharmony_ci	}								   \
154862306a36Sopenharmony_ci									   \
154962306a36Sopenharmony_ci	if (val != 0 && val != 1) {					   \
155062306a36Sopenharmony_ci		pr_err("Illegal boolean value %lu\n", val);		   \
155162306a36Sopenharmony_ci		return -EINVAL;						   \
155262306a36Sopenharmony_ci	}								   \
155362306a36Sopenharmony_ci									   \
155462306a36Sopenharmony_ci	a->name = val;							   \
155562306a36Sopenharmony_ci									   \
155662306a36Sopenharmony_ci	return count;							   \
155762306a36Sopenharmony_ci}									   \
155862306a36Sopenharmony_ciCONFIGFS_ATTR(efct_lio_npiv_tpg_attrib_, name)
155962306a36Sopenharmony_ci
156062306a36Sopenharmony_ciDEF_EFCT_NPIV_TPG_ATTRIB(generate_node_acls);
156162306a36Sopenharmony_ciDEF_EFCT_NPIV_TPG_ATTRIB(cache_dynamic_acls);
156262306a36Sopenharmony_ciDEF_EFCT_NPIV_TPG_ATTRIB(demo_mode_write_protect);
156362306a36Sopenharmony_ciDEF_EFCT_NPIV_TPG_ATTRIB(prod_mode_write_protect);
156462306a36Sopenharmony_ciDEF_EFCT_NPIV_TPG_ATTRIB(demo_mode_login_only);
156562306a36Sopenharmony_ciDEF_EFCT_NPIV_TPG_ATTRIB(session_deletion_wait);
156662306a36Sopenharmony_ci
156762306a36Sopenharmony_cistatic struct configfs_attribute *efct_lio_npiv_tpg_attrib_attrs[] = {
156862306a36Sopenharmony_ci	&efct_lio_npiv_tpg_attrib_attr_generate_node_acls,
156962306a36Sopenharmony_ci	&efct_lio_npiv_tpg_attrib_attr_cache_dynamic_acls,
157062306a36Sopenharmony_ci	&efct_lio_npiv_tpg_attrib_attr_demo_mode_write_protect,
157162306a36Sopenharmony_ci	&efct_lio_npiv_tpg_attrib_attr_prod_mode_write_protect,
157262306a36Sopenharmony_ci	&efct_lio_npiv_tpg_attrib_attr_demo_mode_login_only,
157362306a36Sopenharmony_ci	&efct_lio_npiv_tpg_attrib_attr_session_deletion_wait,
157462306a36Sopenharmony_ci	NULL,
157562306a36Sopenharmony_ci};
157662306a36Sopenharmony_ci
157762306a36Sopenharmony_ciCONFIGFS_ATTR(efct_lio_tpg_, enable);
157862306a36Sopenharmony_cistatic struct configfs_attribute *efct_lio_tpg_attrs[] = {
157962306a36Sopenharmony_ci				&efct_lio_tpg_attr_enable, NULL };
158062306a36Sopenharmony_ciCONFIGFS_ATTR(efct_lio_npiv_tpg_, enable);
158162306a36Sopenharmony_cistatic struct configfs_attribute *efct_lio_npiv_tpg_attrs[] = {
158262306a36Sopenharmony_ci				&efct_lio_npiv_tpg_attr_enable, NULL };
158362306a36Sopenharmony_ci
158462306a36Sopenharmony_cistatic const struct target_core_fabric_ops efct_lio_ops = {
158562306a36Sopenharmony_ci	.module				= THIS_MODULE,
158662306a36Sopenharmony_ci	.fabric_name			= "efct",
158762306a36Sopenharmony_ci	.node_acl_size			= sizeof(struct efct_lio_nacl),
158862306a36Sopenharmony_ci	.max_data_sg_nents		= 65535,
158962306a36Sopenharmony_ci	.tpg_get_wwn			= efct_lio_get_fabric_wwn,
159062306a36Sopenharmony_ci	.tpg_get_tag			= efct_lio_get_tag,
159162306a36Sopenharmony_ci	.fabric_init_nodeacl		= efct_lio_init_nodeacl,
159262306a36Sopenharmony_ci	.tpg_check_demo_mode		= efct_lio_check_demo_mode,
159362306a36Sopenharmony_ci	.tpg_check_demo_mode_cache      = efct_lio_check_demo_mode_cache,
159462306a36Sopenharmony_ci	.tpg_check_demo_mode_write_protect = efct_lio_check_demo_write_protect,
159562306a36Sopenharmony_ci	.tpg_check_prod_mode_write_protect = efct_lio_check_prod_write_protect,
159662306a36Sopenharmony_ci	.check_stop_free		= efct_lio_check_stop_free,
159762306a36Sopenharmony_ci	.aborted_task			= efct_lio_aborted_task,
159862306a36Sopenharmony_ci	.release_cmd			= efct_lio_release_cmd,
159962306a36Sopenharmony_ci	.close_session			= efct_lio_close_session,
160062306a36Sopenharmony_ci	.write_pending			= efct_lio_write_pending,
160162306a36Sopenharmony_ci	.get_cmd_state			= efct_lio_get_cmd_state,
160262306a36Sopenharmony_ci	.queue_data_in			= efct_lio_queue_data_in,
160362306a36Sopenharmony_ci	.queue_status			= efct_lio_queue_status,
160462306a36Sopenharmony_ci	.queue_tm_rsp			= efct_lio_queue_tm_rsp,
160562306a36Sopenharmony_ci	.fabric_make_wwn		= efct_lio_make_nport,
160662306a36Sopenharmony_ci	.fabric_drop_wwn		= efct_lio_drop_nport,
160762306a36Sopenharmony_ci	.fabric_make_tpg		= efct_lio_make_tpg,
160862306a36Sopenharmony_ci	.fabric_drop_tpg		= efct_lio_drop_tpg,
160962306a36Sopenharmony_ci	.tpg_check_demo_mode_login_only = efct_lio_check_demo_mode_login_only,
161062306a36Sopenharmony_ci	.tpg_check_prot_fabric_only	= NULL,
161162306a36Sopenharmony_ci	.sess_get_initiator_sid		= NULL,
161262306a36Sopenharmony_ci	.tfc_tpg_base_attrs		= efct_lio_tpg_attrs,
161362306a36Sopenharmony_ci	.tfc_tpg_attrib_attrs           = efct_lio_tpg_attrib_attrs,
161462306a36Sopenharmony_ci};
161562306a36Sopenharmony_ci
161662306a36Sopenharmony_cistatic const struct target_core_fabric_ops efct_lio_npiv_ops = {
161762306a36Sopenharmony_ci	.module				= THIS_MODULE,
161862306a36Sopenharmony_ci	.fabric_name			= "efct_npiv",
161962306a36Sopenharmony_ci	.node_acl_size			= sizeof(struct efct_lio_nacl),
162062306a36Sopenharmony_ci	.max_data_sg_nents		= 65535,
162162306a36Sopenharmony_ci	.tpg_get_wwn			= efct_lio_get_npiv_fabric_wwn,
162262306a36Sopenharmony_ci	.tpg_get_tag			= efct_lio_get_npiv_tag,
162362306a36Sopenharmony_ci	.fabric_init_nodeacl		= efct_lio_init_nodeacl,
162462306a36Sopenharmony_ci	.tpg_check_demo_mode		= efct_lio_check_demo_mode,
162562306a36Sopenharmony_ci	.tpg_check_demo_mode_cache      = efct_lio_check_demo_mode_cache,
162662306a36Sopenharmony_ci	.tpg_check_demo_mode_write_protect =
162762306a36Sopenharmony_ci					efct_lio_npiv_check_demo_write_protect,
162862306a36Sopenharmony_ci	.tpg_check_prod_mode_write_protect =
162962306a36Sopenharmony_ci					efct_lio_npiv_check_prod_write_protect,
163062306a36Sopenharmony_ci	.check_stop_free		= efct_lio_check_stop_free,
163162306a36Sopenharmony_ci	.aborted_task			= efct_lio_aborted_task,
163262306a36Sopenharmony_ci	.release_cmd			= efct_lio_release_cmd,
163362306a36Sopenharmony_ci	.close_session			= efct_lio_close_session,
163462306a36Sopenharmony_ci	.write_pending			= efct_lio_write_pending,
163562306a36Sopenharmony_ci	.get_cmd_state			= efct_lio_get_cmd_state,
163662306a36Sopenharmony_ci	.queue_data_in			= efct_lio_queue_data_in,
163762306a36Sopenharmony_ci	.queue_status			= efct_lio_queue_status,
163862306a36Sopenharmony_ci	.queue_tm_rsp			= efct_lio_queue_tm_rsp,
163962306a36Sopenharmony_ci	.fabric_make_wwn		= efct_lio_npiv_make_nport,
164062306a36Sopenharmony_ci	.fabric_drop_wwn		= efct_lio_npiv_drop_nport,
164162306a36Sopenharmony_ci	.fabric_make_tpg		= efct_lio_npiv_make_tpg,
164262306a36Sopenharmony_ci	.fabric_drop_tpg		= efct_lio_npiv_drop_tpg,
164362306a36Sopenharmony_ci	.tpg_check_demo_mode_login_only =
164462306a36Sopenharmony_ci				efct_lio_npiv_check_demo_mode_login_only,
164562306a36Sopenharmony_ci	.tpg_check_prot_fabric_only	= NULL,
164662306a36Sopenharmony_ci	.sess_get_initiator_sid		= NULL,
164762306a36Sopenharmony_ci	.tfc_tpg_base_attrs		= efct_lio_npiv_tpg_attrs,
164862306a36Sopenharmony_ci	.tfc_tpg_attrib_attrs		= efct_lio_npiv_tpg_attrib_attrs,
164962306a36Sopenharmony_ci};
165062306a36Sopenharmony_ci
165162306a36Sopenharmony_ciint efct_scsi_tgt_driver_init(void)
165262306a36Sopenharmony_ci{
165362306a36Sopenharmony_ci	int rc;
165462306a36Sopenharmony_ci
165562306a36Sopenharmony_ci	/* Register the top level struct config_item_type with TCM core */
165662306a36Sopenharmony_ci	rc = target_register_template(&efct_lio_ops);
165762306a36Sopenharmony_ci	if (rc < 0) {
165862306a36Sopenharmony_ci		pr_err("target_fabric_configfs_register failed with %d\n", rc);
165962306a36Sopenharmony_ci		return rc;
166062306a36Sopenharmony_ci	}
166162306a36Sopenharmony_ci	rc = target_register_template(&efct_lio_npiv_ops);
166262306a36Sopenharmony_ci	if (rc < 0) {
166362306a36Sopenharmony_ci		pr_err("target_fabric_configfs_register failed with %d\n", rc);
166462306a36Sopenharmony_ci		target_unregister_template(&efct_lio_ops);
166562306a36Sopenharmony_ci		return rc;
166662306a36Sopenharmony_ci	}
166762306a36Sopenharmony_ci	return 0;
166862306a36Sopenharmony_ci}
166962306a36Sopenharmony_ci
167062306a36Sopenharmony_ciint efct_scsi_tgt_driver_exit(void)
167162306a36Sopenharmony_ci{
167262306a36Sopenharmony_ci	target_unregister_template(&efct_lio_ops);
167362306a36Sopenharmony_ci	target_unregister_template(&efct_lio_npiv_ops);
167462306a36Sopenharmony_ci	return 0;
167562306a36Sopenharmony_ci}
1676