xref: /openbmc/linux/drivers/scsi/elx/efct/efct_lio.c (revision 1ac731c529cd4d6adbce134754b51ff7d822b145)
1692e5d73SJames Smart // SPDX-License-Identifier: GPL-2.0
2692e5d73SJames Smart /*
3692e5d73SJames Smart  * Copyright (C) 2021 Broadcom. All Rights Reserved. The term
4692e5d73SJames Smart  * “Broadcom” refers to Broadcom Inc. and/or its subsidiaries.
5692e5d73SJames Smart  */
6692e5d73SJames Smart 
7692e5d73SJames Smart #include <target/target_core_base.h>
8692e5d73SJames Smart #include <target/target_core_fabric.h>
9692e5d73SJames Smart #include "efct_driver.h"
10692e5d73SJames Smart #include "efct_lio.h"
11692e5d73SJames Smart 
12692e5d73SJames Smart /*
13692e5d73SJames Smart  * lio_wq is used to call the LIO backed during creation or deletion of
14692e5d73SJames Smart  * sessions. This brings serialization to the session management as we create
15692e5d73SJames Smart  * single threaded work queue.
16692e5d73SJames Smart  */
17692e5d73SJames Smart static struct workqueue_struct *lio_wq;
18692e5d73SJames Smart 
19692e5d73SJames Smart static int
efct_format_wwn(char * str,size_t len,const char * pre,u64 wwn)20692e5d73SJames Smart efct_format_wwn(char *str, size_t len, const char *pre, u64 wwn)
21692e5d73SJames Smart {
22692e5d73SJames Smart 	u8 a[8];
23692e5d73SJames Smart 
24692e5d73SJames Smart 	put_unaligned_be64(wwn, a);
25692e5d73SJames Smart 	return snprintf(str, len, "%s%8phC", pre, a);
26692e5d73SJames Smart }
27692e5d73SJames Smart 
28692e5d73SJames Smart static int
efct_lio_parse_wwn(const char * name,u64 * wwp,u8 npiv)29692e5d73SJames Smart efct_lio_parse_wwn(const char *name, u64 *wwp, u8 npiv)
30692e5d73SJames Smart {
31692e5d73SJames Smart 	int num;
32692e5d73SJames Smart 	u8 b[8];
33692e5d73SJames Smart 
34692e5d73SJames Smart 	if (npiv) {
35692e5d73SJames Smart 		num = sscanf(name,
36692e5d73SJames Smart 			     "%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx",
37692e5d73SJames Smart 			     &b[0], &b[1], &b[2], &b[3], &b[4], &b[5], &b[6],
38692e5d73SJames Smart 			     &b[7]);
39692e5d73SJames Smart 	} else {
40692e5d73SJames Smart 		num = sscanf(name,
41692e5d73SJames Smart 		      "%02hhx:%02hhx:%02hhx:%02hhx:%02hhx:%02hhx:%02hhx:%02hhx",
42692e5d73SJames Smart 			     &b[0], &b[1], &b[2], &b[3], &b[4], &b[5], &b[6],
43692e5d73SJames Smart 			     &b[7]);
44692e5d73SJames Smart 	}
45692e5d73SJames Smart 
46692e5d73SJames Smart 	if (num != 8)
47692e5d73SJames Smart 		return -EINVAL;
48692e5d73SJames Smart 
49692e5d73SJames Smart 	*wwp = get_unaligned_be64(b);
50692e5d73SJames Smart 	return 0;
51692e5d73SJames Smart }
52692e5d73SJames Smart 
53692e5d73SJames Smart static int
efct_lio_parse_npiv_wwn(const char * name,size_t size,u64 * wwpn,u64 * wwnn)54692e5d73SJames Smart efct_lio_parse_npiv_wwn(const char *name, size_t size, u64 *wwpn, u64 *wwnn)
55692e5d73SJames Smart {
56692e5d73SJames Smart 	unsigned int cnt = size;
57692e5d73SJames Smart 	int rc;
58692e5d73SJames Smart 
59692e5d73SJames Smart 	*wwpn = *wwnn = 0;
60692e5d73SJames Smart 	if (name[cnt - 1] == '\n' || name[cnt - 1] == 0)
61692e5d73SJames Smart 		cnt--;
62692e5d73SJames Smart 
63692e5d73SJames Smart 	/* validate we have enough characters for WWPN */
64692e5d73SJames Smart 	if ((cnt != (16 + 1 + 16)) || (name[16] != ':'))
65692e5d73SJames Smart 		return -EINVAL;
66692e5d73SJames Smart 
67692e5d73SJames Smart 	rc = efct_lio_parse_wwn(&name[0], wwpn, 1);
68692e5d73SJames Smart 	if (rc)
69692e5d73SJames Smart 		return rc;
70692e5d73SJames Smart 
71692e5d73SJames Smart 	rc = efct_lio_parse_wwn(&name[17], wwnn, 1);
72692e5d73SJames Smart 	if (rc)
73692e5d73SJames Smart 		return rc;
74692e5d73SJames Smart 
75692e5d73SJames Smart 	return 0;
76692e5d73SJames Smart }
77692e5d73SJames Smart 
78692e5d73SJames Smart static ssize_t
efct_lio_tpg_enable_show(struct config_item * item,char * page)79692e5d73SJames Smart efct_lio_tpg_enable_show(struct config_item *item, char *page)
80692e5d73SJames Smart {
81692e5d73SJames Smart 	struct se_portal_group *se_tpg = to_tpg(item);
82692e5d73SJames Smart 	struct efct_lio_tpg *tpg =
83692e5d73SJames Smart 		container_of(se_tpg, struct efct_lio_tpg, tpg);
84692e5d73SJames Smart 
85692e5d73SJames Smart 	return snprintf(page, PAGE_SIZE, "%d\n", tpg->enabled);
86692e5d73SJames Smart }
87692e5d73SJames Smart 
88692e5d73SJames Smart static ssize_t
efct_lio_tpg_enable_store(struct config_item * item,const char * page,size_t count)89692e5d73SJames Smart efct_lio_tpg_enable_store(struct config_item *item, const char *page,
90692e5d73SJames Smart 			  size_t count)
91692e5d73SJames Smart {
92692e5d73SJames Smart 	struct se_portal_group *se_tpg = to_tpg(item);
93692e5d73SJames Smart 	struct efct_lio_tpg *tpg =
94692e5d73SJames Smart 		container_of(se_tpg, struct efct_lio_tpg, tpg);
95692e5d73SJames Smart 	struct efct *efct;
96692e5d73SJames Smart 	struct efc *efc;
97692e5d73SJames Smart 	unsigned long op;
98692e5d73SJames Smart 
99692e5d73SJames Smart 	if (!tpg->nport || !tpg->nport->efct) {
100692e5d73SJames Smart 		pr_err("%s: Unable to find EFCT device\n", __func__);
101692e5d73SJames Smart 		return -EINVAL;
102692e5d73SJames Smart 	}
103692e5d73SJames Smart 
104692e5d73SJames Smart 	efct = tpg->nport->efct;
105692e5d73SJames Smart 	efc = efct->efcport;
106692e5d73SJames Smart 
107692e5d73SJames Smart 	if (kstrtoul(page, 0, &op) < 0)
108692e5d73SJames Smart 		return -EINVAL;
109692e5d73SJames Smart 
110692e5d73SJames Smart 	if (op == 1) {
111692e5d73SJames Smart 		int ret;
112692e5d73SJames Smart 
113692e5d73SJames Smart 		tpg->enabled = true;
114692e5d73SJames Smart 		efc_log_debug(efct, "enable portal group %d\n", tpg->tpgt);
115692e5d73SJames Smart 
116692e5d73SJames Smart 		ret = efct_xport_control(efct->xport, EFCT_XPORT_PORT_ONLINE);
117692e5d73SJames Smart 		if (ret) {
118692e5d73SJames Smart 			efct->tgt_efct.lio_nport = NULL;
119692e5d73SJames Smart 			efc_log_debug(efct, "cannot bring port online\n");
120692e5d73SJames Smart 			return ret;
121692e5d73SJames Smart 		}
122692e5d73SJames Smart 	} else if (op == 0) {
123692e5d73SJames Smart 		efc_log_debug(efct, "disable portal group %d\n", tpg->tpgt);
124692e5d73SJames Smart 
125692e5d73SJames Smart 		if (efc->domain && efc->domain->nport)
126692e5d73SJames Smart 			efct_scsi_tgt_del_nport(efc, efc->domain->nport);
127692e5d73SJames Smart 
128692e5d73SJames Smart 		tpg->enabled = false;
129692e5d73SJames Smart 	} else {
130692e5d73SJames Smart 		return -EINVAL;
131692e5d73SJames Smart 	}
132692e5d73SJames Smart 
133692e5d73SJames Smart 	return count;
134692e5d73SJames Smart }
135692e5d73SJames Smart 
136692e5d73SJames Smart static ssize_t
efct_lio_npiv_tpg_enable_show(struct config_item * item,char * page)137692e5d73SJames Smart efct_lio_npiv_tpg_enable_show(struct config_item *item, char *page)
138692e5d73SJames Smart {
139692e5d73SJames Smart 	struct se_portal_group *se_tpg = to_tpg(item);
140692e5d73SJames Smart 	struct efct_lio_tpg *tpg =
141692e5d73SJames Smart 		container_of(se_tpg, struct efct_lio_tpg, tpg);
142692e5d73SJames Smart 
143692e5d73SJames Smart 	return snprintf(page, PAGE_SIZE, "%d\n", tpg->enabled);
144692e5d73SJames Smart }
145692e5d73SJames Smart 
146692e5d73SJames Smart static ssize_t
efct_lio_npiv_tpg_enable_store(struct config_item * item,const char * page,size_t count)147692e5d73SJames Smart efct_lio_npiv_tpg_enable_store(struct config_item *item, const char *page,
148692e5d73SJames Smart 			       size_t count)
149692e5d73SJames Smart {
150692e5d73SJames Smart 	struct se_portal_group *se_tpg = to_tpg(item);
151692e5d73SJames Smart 	struct efct_lio_tpg *tpg =
152692e5d73SJames Smart 		container_of(se_tpg, struct efct_lio_tpg, tpg);
153692e5d73SJames Smart 	struct efct_lio_vport *lio_vport = tpg->vport;
154692e5d73SJames Smart 	struct efct *efct;
155692e5d73SJames Smart 	struct efc *efc;
156692e5d73SJames Smart 	unsigned long op;
157692e5d73SJames Smart 
158692e5d73SJames Smart 	if (kstrtoul(page, 0, &op) < 0)
159692e5d73SJames Smart 		return -EINVAL;
160692e5d73SJames Smart 
161692e5d73SJames Smart 	if (!lio_vport) {
162692e5d73SJames Smart 		pr_err("Unable to find vport\n");
163692e5d73SJames Smart 		return -EINVAL;
164692e5d73SJames Smart 	}
165692e5d73SJames Smart 
166692e5d73SJames Smart 	efct = lio_vport->efct;
167692e5d73SJames Smart 	efc = efct->efcport;
168692e5d73SJames Smart 
169692e5d73SJames Smart 	if (op == 1) {
170692e5d73SJames Smart 		tpg->enabled = true;
171692e5d73SJames Smart 		efc_log_debug(efct, "enable portal group %d\n", tpg->tpgt);
172692e5d73SJames Smart 
173692e5d73SJames Smart 		if (efc->domain) {
174692e5d73SJames Smart 			int ret;
175692e5d73SJames Smart 
176692e5d73SJames Smart 			ret = efc_nport_vport_new(efc->domain,
177692e5d73SJames Smart 						  lio_vport->npiv_wwpn,
178692e5d73SJames Smart 						  lio_vport->npiv_wwnn,
179692e5d73SJames Smart 						  U32_MAX, false, true,
180692e5d73SJames Smart 						  NULL, NULL);
181692e5d73SJames Smart 			if (ret != 0) {
182692e5d73SJames Smart 				efc_log_err(efct, "Failed to create Vport\n");
183692e5d73SJames Smart 				return ret;
184692e5d73SJames Smart 			}
185692e5d73SJames Smart 			return count;
186692e5d73SJames Smart 		}
187692e5d73SJames Smart 
188692e5d73SJames Smart 		if (!(efc_vport_create_spec(efc, lio_vport->npiv_wwnn,
189692e5d73SJames Smart 					    lio_vport->npiv_wwpn, U32_MAX,
190692e5d73SJames Smart 					    false, true, NULL, NULL)))
191692e5d73SJames Smart 			return -ENOMEM;
192692e5d73SJames Smart 
193692e5d73SJames Smart 	} else if (op == 0) {
194692e5d73SJames Smart 		efc_log_debug(efct, "disable portal group %d\n", tpg->tpgt);
195692e5d73SJames Smart 
196692e5d73SJames Smart 		tpg->enabled = false;
197692e5d73SJames Smart 		/* only physical nport should exist, free lio_nport
198692e5d73SJames Smart 		 * allocated in efct_lio_make_nport
199692e5d73SJames Smart 		 */
200692e5d73SJames Smart 		if (efc->domain) {
201692e5d73SJames Smart 			efc_nport_vport_del(efct->efcport, efc->domain,
202692e5d73SJames Smart 					    lio_vport->npiv_wwpn,
203692e5d73SJames Smart 					    lio_vport->npiv_wwnn);
204692e5d73SJames Smart 			return count;
205692e5d73SJames Smart 		}
206692e5d73SJames Smart 	} else {
207692e5d73SJames Smart 		return -EINVAL;
208692e5d73SJames Smart 	}
209692e5d73SJames Smart 	return count;
210692e5d73SJames Smart }
211692e5d73SJames Smart 
efct_lio_get_fabric_wwn(struct se_portal_group * se_tpg)212692e5d73SJames Smart static char *efct_lio_get_fabric_wwn(struct se_portal_group *se_tpg)
213692e5d73SJames Smart {
214692e5d73SJames Smart 	struct efct_lio_tpg *tpg =
215692e5d73SJames Smart 		container_of(se_tpg, struct efct_lio_tpg, tpg);
216692e5d73SJames Smart 
217692e5d73SJames Smart 	return tpg->nport->wwpn_str;
218692e5d73SJames Smart }
219692e5d73SJames Smart 
efct_lio_get_npiv_fabric_wwn(struct se_portal_group * se_tpg)220692e5d73SJames Smart static char *efct_lio_get_npiv_fabric_wwn(struct se_portal_group *se_tpg)
221692e5d73SJames Smart {
222692e5d73SJames Smart 	struct efct_lio_tpg *tpg =
223692e5d73SJames Smart 		container_of(se_tpg, struct efct_lio_tpg, tpg);
224692e5d73SJames Smart 
225692e5d73SJames Smart 	return tpg->vport->wwpn_str;
226692e5d73SJames Smart }
227692e5d73SJames Smart 
efct_lio_get_tag(struct se_portal_group * se_tpg)228692e5d73SJames Smart static u16 efct_lio_get_tag(struct se_portal_group *se_tpg)
229692e5d73SJames Smart {
230692e5d73SJames Smart 	struct efct_lio_tpg *tpg =
231692e5d73SJames Smart 		container_of(se_tpg, struct efct_lio_tpg, tpg);
232692e5d73SJames Smart 
233692e5d73SJames Smart 	return tpg->tpgt;
234692e5d73SJames Smart }
235692e5d73SJames Smart 
efct_lio_get_npiv_tag(struct se_portal_group * se_tpg)236692e5d73SJames Smart static u16 efct_lio_get_npiv_tag(struct se_portal_group *se_tpg)
237692e5d73SJames Smart {
238692e5d73SJames Smart 	struct efct_lio_tpg *tpg =
239692e5d73SJames Smart 		container_of(se_tpg, struct efct_lio_tpg, tpg);
240692e5d73SJames Smart 
241692e5d73SJames Smart 	return tpg->tpgt;
242692e5d73SJames Smart }
243692e5d73SJames Smart 
efct_lio_check_demo_mode(struct se_portal_group * se_tpg)244692e5d73SJames Smart static int efct_lio_check_demo_mode(struct se_portal_group *se_tpg)
245692e5d73SJames Smart {
246692e5d73SJames Smart 	return 1;
247692e5d73SJames Smart }
248692e5d73SJames Smart 
efct_lio_check_demo_mode_cache(struct se_portal_group * se_tpg)249692e5d73SJames Smart static int efct_lio_check_demo_mode_cache(struct se_portal_group *se_tpg)
250692e5d73SJames Smart {
251692e5d73SJames Smart 	return 1;
252692e5d73SJames Smart }
253692e5d73SJames Smart 
efct_lio_check_demo_write_protect(struct se_portal_group * se_tpg)254692e5d73SJames Smart static int efct_lio_check_demo_write_protect(struct se_portal_group *se_tpg)
255692e5d73SJames Smart {
256692e5d73SJames Smart 	struct efct_lio_tpg *tpg =
257692e5d73SJames Smart 		container_of(se_tpg, struct efct_lio_tpg, tpg);
258692e5d73SJames Smart 
259692e5d73SJames Smart 	return tpg->tpg_attrib.demo_mode_write_protect;
260692e5d73SJames Smart }
261692e5d73SJames Smart 
262692e5d73SJames Smart static int
efct_lio_npiv_check_demo_write_protect(struct se_portal_group * se_tpg)263692e5d73SJames Smart efct_lio_npiv_check_demo_write_protect(struct se_portal_group *se_tpg)
264692e5d73SJames Smart {
265692e5d73SJames Smart 	struct efct_lio_tpg *tpg =
266692e5d73SJames Smart 		container_of(se_tpg, struct efct_lio_tpg, tpg);
267692e5d73SJames Smart 
268692e5d73SJames Smart 	return tpg->tpg_attrib.demo_mode_write_protect;
269692e5d73SJames Smart }
270692e5d73SJames Smart 
efct_lio_check_prod_write_protect(struct se_portal_group * se_tpg)271692e5d73SJames Smart static int efct_lio_check_prod_write_protect(struct se_portal_group *se_tpg)
272692e5d73SJames Smart {
273692e5d73SJames Smart 	struct efct_lio_tpg *tpg =
274692e5d73SJames Smart 		container_of(se_tpg, struct efct_lio_tpg, tpg);
275692e5d73SJames Smart 
276692e5d73SJames Smart 	return tpg->tpg_attrib.prod_mode_write_protect;
277692e5d73SJames Smart }
278692e5d73SJames Smart 
279692e5d73SJames Smart static int
efct_lio_npiv_check_prod_write_protect(struct se_portal_group * se_tpg)280692e5d73SJames Smart efct_lio_npiv_check_prod_write_protect(struct se_portal_group *se_tpg)
281692e5d73SJames Smart {
282692e5d73SJames Smart 	struct efct_lio_tpg *tpg =
283692e5d73SJames Smart 		container_of(se_tpg, struct efct_lio_tpg, tpg);
284692e5d73SJames Smart 
285692e5d73SJames Smart 	return tpg->tpg_attrib.prod_mode_write_protect;
286692e5d73SJames Smart }
287692e5d73SJames Smart 
efct_lio_check_stop_free(struct se_cmd * se_cmd)288692e5d73SJames Smart static int efct_lio_check_stop_free(struct se_cmd *se_cmd)
289692e5d73SJames Smart {
290692e5d73SJames Smart 	struct efct_scsi_tgt_io *ocp =
291692e5d73SJames Smart 		container_of(se_cmd, struct efct_scsi_tgt_io, cmd);
292692e5d73SJames Smart 	struct efct_io *io = container_of(ocp, struct efct_io, tgt_io);
293692e5d73SJames Smart 
294692e5d73SJames Smart 	efct_set_lio_io_state(io, EFCT_LIO_STATE_TFO_CHK_STOP_FREE);
295692e5d73SJames Smart 	return target_put_sess_cmd(se_cmd);
296692e5d73SJames Smart }
297692e5d73SJames Smart 
298692e5d73SJames Smart static int
efct_lio_abort_tgt_cb(struct efct_io * io,enum efct_scsi_io_status scsi_status,u32 flags,void * arg)299692e5d73SJames Smart efct_lio_abort_tgt_cb(struct efct_io *io,
300692e5d73SJames Smart 		      enum efct_scsi_io_status scsi_status,
301692e5d73SJames Smart 		      u32 flags, void *arg)
302692e5d73SJames Smart {
303692e5d73SJames Smart 	efct_lio_io_printf(io, "Abort done, status:%d\n", scsi_status);
304692e5d73SJames Smart 	return 0;
305692e5d73SJames Smart }
306692e5d73SJames Smart 
307692e5d73SJames Smart static void
efct_lio_aborted_task(struct se_cmd * se_cmd)308692e5d73SJames Smart efct_lio_aborted_task(struct se_cmd *se_cmd)
309692e5d73SJames Smart {
310692e5d73SJames Smart 	struct efct_scsi_tgt_io *ocp =
311692e5d73SJames Smart 		container_of(se_cmd, struct efct_scsi_tgt_io, cmd);
312692e5d73SJames Smart 	struct efct_io *io = container_of(ocp, struct efct_io, tgt_io);
313692e5d73SJames Smart 
314692e5d73SJames Smart 	efct_set_lio_io_state(io, EFCT_LIO_STATE_TFO_ABORTED_TASK);
315692e5d73SJames Smart 
316692e5d73SJames Smart 	if (ocp->rsp_sent)
317692e5d73SJames Smart 		return;
318692e5d73SJames Smart 
319692e5d73SJames Smart 	/* command has been aborted, cleanup here */
320692e5d73SJames Smart 	ocp->aborting = true;
321692e5d73SJames Smart 	ocp->err = EFCT_SCSI_STATUS_ABORTED;
322692e5d73SJames Smart 	/* terminate the exchange */
323692e5d73SJames Smart 	efct_scsi_tgt_abort_io(io, efct_lio_abort_tgt_cb, NULL);
324692e5d73SJames Smart }
325692e5d73SJames Smart 
efct_lio_release_cmd(struct se_cmd * se_cmd)326692e5d73SJames Smart static void efct_lio_release_cmd(struct se_cmd *se_cmd)
327692e5d73SJames Smart {
328692e5d73SJames Smart 	struct efct_scsi_tgt_io *ocp =
329692e5d73SJames Smart 		container_of(se_cmd, struct efct_scsi_tgt_io, cmd);
330692e5d73SJames Smart 	struct efct_io *io = container_of(ocp, struct efct_io, tgt_io);
331692e5d73SJames Smart 	struct efct *efct = io->efct;
332692e5d73SJames Smart 
333692e5d73SJames Smart 	efct_set_lio_io_state(io, EFCT_LIO_STATE_TFO_RELEASE_CMD);
334692e5d73SJames Smart 	efct_set_lio_io_state(io, EFCT_LIO_STATE_SCSI_CMPL_CMD);
335692e5d73SJames Smart 	efct_scsi_io_complete(io);
336692e5d73SJames Smart 	atomic_sub_return(1, &efct->tgt_efct.ios_in_use);
337692e5d73SJames Smart }
338692e5d73SJames Smart 
efct_lio_close_session(struct se_session * se_sess)339692e5d73SJames Smart static void efct_lio_close_session(struct se_session *se_sess)
340692e5d73SJames Smart {
341692e5d73SJames Smart 	struct efc_node *node = se_sess->fabric_sess_ptr;
342692e5d73SJames Smart 
343692e5d73SJames Smart 	pr_debug("se_sess=%p node=%p", se_sess, node);
344692e5d73SJames Smart 
345692e5d73SJames Smart 	if (!node) {
346692e5d73SJames Smart 		pr_debug("node is NULL");
347692e5d73SJames Smart 		return;
348692e5d73SJames Smart 	}
349692e5d73SJames Smart 
350692e5d73SJames Smart 	efc_node_post_shutdown(node, NULL);
351692e5d73SJames Smart }
352692e5d73SJames Smart 
efct_lio_get_cmd_state(struct se_cmd * cmd)353692e5d73SJames Smart static int efct_lio_get_cmd_state(struct se_cmd *cmd)
354692e5d73SJames Smart {
355692e5d73SJames Smart 	struct efct_scsi_tgt_io *ocp =
356692e5d73SJames Smart 		container_of(cmd, struct efct_scsi_tgt_io, cmd);
357692e5d73SJames Smart 	struct efct_io *io = container_of(ocp, struct efct_io, tgt_io);
358692e5d73SJames Smart 
359692e5d73SJames Smart 	return io->tgt_io.state;
360692e5d73SJames Smart }
361692e5d73SJames Smart 
362692e5d73SJames Smart static int
efct_lio_sg_map(struct efct_io * io)363692e5d73SJames Smart efct_lio_sg_map(struct efct_io *io)
364692e5d73SJames Smart {
365692e5d73SJames Smart 	struct efct_scsi_tgt_io *ocp = &io->tgt_io;
366692e5d73SJames Smart 	struct se_cmd *cmd = &ocp->cmd;
367692e5d73SJames Smart 
368*ca4ff9e7SChristophe JAILLET 	ocp->seg_map_cnt = dma_map_sg(&io->efct->pci->dev, cmd->t_data_sg,
369692e5d73SJames Smart 				      cmd->t_data_nents, cmd->data_direction);
370692e5d73SJames Smart 	if (ocp->seg_map_cnt == 0)
371692e5d73SJames Smart 		return -EFAULT;
372692e5d73SJames Smart 	return 0;
373692e5d73SJames Smart }
374692e5d73SJames Smart 
375692e5d73SJames Smart static void
efct_lio_sg_unmap(struct efct_io * io)376692e5d73SJames Smart efct_lio_sg_unmap(struct efct_io *io)
377692e5d73SJames Smart {
378692e5d73SJames Smart 	struct efct_scsi_tgt_io *ocp = &io->tgt_io;
379692e5d73SJames Smart 	struct se_cmd *cmd = &ocp->cmd;
380692e5d73SJames Smart 
381692e5d73SJames Smart 	if (WARN_ON(!ocp->seg_map_cnt || !cmd->t_data_sg))
382692e5d73SJames Smart 		return;
383692e5d73SJames Smart 
384*ca4ff9e7SChristophe JAILLET 	dma_unmap_sg(&io->efct->pci->dev, cmd->t_data_sg,
385692e5d73SJames Smart 		     ocp->seg_map_cnt, cmd->data_direction);
386692e5d73SJames Smart 	ocp->seg_map_cnt = 0;
387692e5d73SJames Smart }
388692e5d73SJames Smart 
389692e5d73SJames Smart static int
efct_lio_status_done(struct efct_io * io,enum efct_scsi_io_status scsi_status,u32 flags,void * arg)390692e5d73SJames Smart efct_lio_status_done(struct efct_io *io,
391692e5d73SJames Smart 		     enum efct_scsi_io_status scsi_status,
392692e5d73SJames Smart 		     u32 flags, void *arg)
393692e5d73SJames Smart {
394692e5d73SJames Smart 	struct efct_scsi_tgt_io *ocp = &io->tgt_io;
395692e5d73SJames Smart 
396692e5d73SJames Smart 	efct_set_lio_io_state(io, EFCT_LIO_STATE_SCSI_RSP_DONE);
397692e5d73SJames Smart 	if (scsi_status != EFCT_SCSI_STATUS_GOOD) {
398692e5d73SJames Smart 		efct_lio_io_printf(io, "callback completed with error=%d\n",
399692e5d73SJames Smart 				   scsi_status);
400692e5d73SJames Smart 		ocp->err = scsi_status;
401692e5d73SJames Smart 	}
402692e5d73SJames Smart 	if (ocp->seg_map_cnt)
403692e5d73SJames Smart 		efct_lio_sg_unmap(io);
404692e5d73SJames Smart 
405692e5d73SJames Smart 	efct_lio_io_printf(io, "status=%d, err=%d flags=0x%x, dir=%d\n",
406692e5d73SJames Smart 			   scsi_status, ocp->err, flags, ocp->ddir);
407692e5d73SJames Smart 
408692e5d73SJames Smart 	efct_set_lio_io_state(io, EFCT_LIO_STATE_TGT_GENERIC_FREE);
409692e5d73SJames Smart 	transport_generic_free_cmd(&io->tgt_io.cmd, 0);
410692e5d73SJames Smart 	return 0;
411692e5d73SJames Smart }
412692e5d73SJames Smart 
413692e5d73SJames Smart static int
414692e5d73SJames Smart efct_lio_datamove_done(struct efct_io *io, enum efct_scsi_io_status scsi_status,
415692e5d73SJames Smart 		       u32 flags, void *arg);
416692e5d73SJames Smart 
417692e5d73SJames Smart static int
efct_lio_write_pending(struct se_cmd * cmd)418692e5d73SJames Smart efct_lio_write_pending(struct se_cmd *cmd)
419692e5d73SJames Smart {
420692e5d73SJames Smart 	struct efct_scsi_tgt_io *ocp =
421692e5d73SJames Smart 		container_of(cmd, struct efct_scsi_tgt_io, cmd);
422692e5d73SJames Smart 	struct efct_io *io = container_of(ocp, struct efct_io, tgt_io);
423692e5d73SJames Smart 	struct efct_scsi_sgl *sgl = io->sgl;
424692e5d73SJames Smart 	struct scatterlist *sg;
425692e5d73SJames Smart 	u32 flags = 0, cnt, curcnt;
426692e5d73SJames Smart 	u64 length = 0;
427692e5d73SJames Smart 
428692e5d73SJames Smart 	efct_set_lio_io_state(io, EFCT_LIO_STATE_TFO_WRITE_PENDING);
429692e5d73SJames Smart 	efct_lio_io_printf(io, "trans_state=0x%x se_cmd_flags=0x%x\n",
430692e5d73SJames Smart 			   cmd->transport_state, cmd->se_cmd_flags);
431692e5d73SJames Smart 
432692e5d73SJames Smart 	if (ocp->seg_cnt == 0) {
433692e5d73SJames Smart 		ocp->seg_cnt = cmd->t_data_nents;
434692e5d73SJames Smart 		ocp->cur_seg = 0;
435692e5d73SJames Smart 		if (efct_lio_sg_map(io)) {
436692e5d73SJames Smart 			efct_lio_io_printf(io, "efct_lio_sg_map failed\n");
437692e5d73SJames Smart 			return -EFAULT;
438692e5d73SJames Smart 		}
439692e5d73SJames Smart 	}
440692e5d73SJames Smart 	curcnt = (ocp->seg_map_cnt - ocp->cur_seg);
441692e5d73SJames Smart 	curcnt = (curcnt < io->sgl_allocated) ? curcnt : io->sgl_allocated;
442692e5d73SJames Smart 	/* find current sg */
443692e5d73SJames Smart 	for (cnt = 0, sg = cmd->t_data_sg; cnt < ocp->cur_seg; cnt++,
444692e5d73SJames Smart 	     sg = sg_next(sg))
445692e5d73SJames Smart 		;/* do nothing */
446692e5d73SJames Smart 
447692e5d73SJames Smart 	for (cnt = 0; cnt < curcnt; cnt++, sg = sg_next(sg)) {
448692e5d73SJames Smart 		sgl[cnt].addr = sg_dma_address(sg);
449692e5d73SJames Smart 		sgl[cnt].dif_addr = 0;
450692e5d73SJames Smart 		sgl[cnt].len = sg_dma_len(sg);
451692e5d73SJames Smart 		length += sgl[cnt].len;
452692e5d73SJames Smart 		ocp->cur_seg++;
453692e5d73SJames Smart 	}
454692e5d73SJames Smart 
455692e5d73SJames Smart 	if (ocp->cur_seg == ocp->seg_cnt)
456692e5d73SJames Smart 		flags = EFCT_SCSI_LAST_DATAPHASE;
457692e5d73SJames Smart 
458692e5d73SJames Smart 	return efct_scsi_recv_wr_data(io, flags, sgl, curcnt, length,
459692e5d73SJames Smart 				    efct_lio_datamove_done, NULL);
460692e5d73SJames Smart }
461692e5d73SJames Smart 
462692e5d73SJames Smart static int
efct_lio_queue_data_in(struct se_cmd * cmd)463692e5d73SJames Smart efct_lio_queue_data_in(struct se_cmd *cmd)
464692e5d73SJames Smart {
465692e5d73SJames Smart 	struct efct_scsi_tgt_io *ocp =
466692e5d73SJames Smart 		container_of(cmd, struct efct_scsi_tgt_io, cmd);
467692e5d73SJames Smart 	struct efct_io *io = container_of(ocp, struct efct_io, tgt_io);
468692e5d73SJames Smart 	struct efct_scsi_sgl *sgl = io->sgl;
469692e5d73SJames Smart 	struct scatterlist *sg = NULL;
470692e5d73SJames Smart 	uint flags = 0, cnt = 0, curcnt = 0;
471692e5d73SJames Smart 	u64 length = 0;
472692e5d73SJames Smart 
473692e5d73SJames Smart 	efct_set_lio_io_state(io, EFCT_LIO_STATE_TFO_QUEUE_DATA_IN);
474692e5d73SJames Smart 
475692e5d73SJames Smart 	if (ocp->seg_cnt == 0) {
476692e5d73SJames Smart 		if (cmd->data_length) {
477692e5d73SJames Smart 			ocp->seg_cnt = cmd->t_data_nents;
478692e5d73SJames Smart 			ocp->cur_seg = 0;
479692e5d73SJames Smart 			if (efct_lio_sg_map(io)) {
480692e5d73SJames Smart 				efct_lio_io_printf(io,
481692e5d73SJames Smart 						   "efct_lio_sg_map failed\n");
482692e5d73SJames Smart 				return -EAGAIN;
483692e5d73SJames Smart 			}
484692e5d73SJames Smart 		} else {
485692e5d73SJames Smart 			/* If command length is 0, send the response status */
486692e5d73SJames Smart 			struct efct_scsi_cmd_resp rsp;
487692e5d73SJames Smart 
488692e5d73SJames Smart 			memset(&rsp, 0, sizeof(rsp));
489692e5d73SJames Smart 			efct_lio_io_printf(io,
490692e5d73SJames Smart 					   "cmd : %p length 0, send status\n",
491692e5d73SJames Smart 					   cmd);
492692e5d73SJames Smart 			return efct_scsi_send_resp(io, 0, &rsp,
493692e5d73SJames Smart 						   efct_lio_status_done, NULL);
494692e5d73SJames Smart 		}
495692e5d73SJames Smart 	}
496692e5d73SJames Smart 	curcnt = min(ocp->seg_map_cnt - ocp->cur_seg, io->sgl_allocated);
497692e5d73SJames Smart 
498692e5d73SJames Smart 	while (cnt < curcnt) {
499692e5d73SJames Smart 		sg = &cmd->t_data_sg[ocp->cur_seg];
500692e5d73SJames Smart 		sgl[cnt].addr = sg_dma_address(sg);
501692e5d73SJames Smart 		sgl[cnt].dif_addr = 0;
502692e5d73SJames Smart 		if (ocp->transferred_len + sg_dma_len(sg) >= cmd->data_length)
503692e5d73SJames Smart 			sgl[cnt].len = cmd->data_length - ocp->transferred_len;
504692e5d73SJames Smart 		else
505692e5d73SJames Smart 			sgl[cnt].len = sg_dma_len(sg);
506692e5d73SJames Smart 
507692e5d73SJames Smart 		ocp->transferred_len += sgl[cnt].len;
508692e5d73SJames Smart 		length += sgl[cnt].len;
509692e5d73SJames Smart 		ocp->cur_seg++;
510692e5d73SJames Smart 		cnt++;
511692e5d73SJames Smart 		if (ocp->transferred_len == cmd->data_length)
512692e5d73SJames Smart 			break;
513692e5d73SJames Smart 	}
514692e5d73SJames Smart 
515692e5d73SJames Smart 	if (ocp->transferred_len == cmd->data_length) {
516692e5d73SJames Smart 		flags = EFCT_SCSI_LAST_DATAPHASE;
517692e5d73SJames Smart 		ocp->seg_cnt = ocp->cur_seg;
518692e5d73SJames Smart 	}
519692e5d73SJames Smart 
520692e5d73SJames Smart 	/* If there is residual, disable Auto Good Response */
521692e5d73SJames Smart 	if (cmd->residual_count)
522692e5d73SJames Smart 		flags |= EFCT_SCSI_NO_AUTO_RESPONSE;
523692e5d73SJames Smart 
524692e5d73SJames Smart 	efct_set_lio_io_state(io, EFCT_LIO_STATE_SCSI_SEND_RD_DATA);
525692e5d73SJames Smart 
526692e5d73SJames Smart 	return efct_scsi_send_rd_data(io, flags, sgl, curcnt, length,
527692e5d73SJames Smart 				    efct_lio_datamove_done, NULL);
528692e5d73SJames Smart }
529692e5d73SJames Smart 
530692e5d73SJames Smart static void
efct_lio_send_resp(struct efct_io * io,enum efct_scsi_io_status scsi_status,u32 flags)531692e5d73SJames Smart efct_lio_send_resp(struct efct_io *io, enum efct_scsi_io_status scsi_status,
532692e5d73SJames Smart 		   u32 flags)
533692e5d73SJames Smart {
534692e5d73SJames Smart 	struct efct_scsi_cmd_resp rsp;
535692e5d73SJames Smart 	struct efct_scsi_tgt_io *ocp = &io->tgt_io;
536692e5d73SJames Smart 	struct se_cmd *cmd = &io->tgt_io.cmd;
537692e5d73SJames Smart 	int rc;
538692e5d73SJames Smart 
539692e5d73SJames Smart 	if (flags & EFCT_SCSI_IO_CMPL_RSP_SENT) {
540692e5d73SJames Smart 		ocp->rsp_sent = true;
541692e5d73SJames Smart 		efct_set_lio_io_state(io, EFCT_LIO_STATE_TGT_GENERIC_FREE);
542692e5d73SJames Smart 		transport_generic_free_cmd(&io->tgt_io.cmd, 0);
543692e5d73SJames Smart 		return;
544692e5d73SJames Smart 	}
545692e5d73SJames Smart 
546692e5d73SJames Smart 	/* send check condition if an error occurred */
547692e5d73SJames Smart 	memset(&rsp, 0, sizeof(rsp));
548692e5d73SJames Smart 	rsp.scsi_status = cmd->scsi_status;
549692e5d73SJames Smart 	rsp.sense_data = (uint8_t *)io->tgt_io.sense_buffer;
550692e5d73SJames Smart 	rsp.sense_data_length = cmd->scsi_sense_length;
551692e5d73SJames Smart 
552692e5d73SJames Smart 	/* Check for residual underrun or overrun */
553692e5d73SJames Smart 	if (cmd->se_cmd_flags & SCF_OVERFLOW_BIT)
554692e5d73SJames Smart 		rsp.residual = -cmd->residual_count;
555692e5d73SJames Smart 	else if (cmd->se_cmd_flags & SCF_UNDERFLOW_BIT)
556692e5d73SJames Smart 		rsp.residual = cmd->residual_count;
557692e5d73SJames Smart 
558692e5d73SJames Smart 	rc = efct_scsi_send_resp(io, 0, &rsp, efct_lio_status_done, NULL);
559692e5d73SJames Smart 	efct_set_lio_io_state(io, EFCT_LIO_STATE_SCSI_SEND_RSP);
560692e5d73SJames Smart 	if (rc != 0) {
561692e5d73SJames Smart 		efct_lio_io_printf(io, "Read done, send rsp failed %d\n", rc);
562692e5d73SJames Smart 		efct_set_lio_io_state(io, EFCT_LIO_STATE_TGT_GENERIC_FREE);
563692e5d73SJames Smart 		transport_generic_free_cmd(&io->tgt_io.cmd, 0);
564692e5d73SJames Smart 	} else {
565692e5d73SJames Smart 		ocp->rsp_sent = true;
566692e5d73SJames Smart 	}
567692e5d73SJames Smart }
568692e5d73SJames Smart 
569692e5d73SJames Smart static int
efct_lio_datamove_done(struct efct_io * io,enum efct_scsi_io_status scsi_status,u32 flags,void * arg)570692e5d73SJames Smart efct_lio_datamove_done(struct efct_io *io, enum efct_scsi_io_status scsi_status,
571692e5d73SJames Smart 		       u32 flags, void *arg)
572692e5d73SJames Smart {
573692e5d73SJames Smart 	struct efct_scsi_tgt_io *ocp = &io->tgt_io;
574692e5d73SJames Smart 
575692e5d73SJames Smart 	efct_set_lio_io_state(io, EFCT_LIO_STATE_SCSI_DATA_DONE);
576692e5d73SJames Smart 	if (scsi_status != EFCT_SCSI_STATUS_GOOD) {
577692e5d73SJames Smart 		efct_lio_io_printf(io, "callback completed with error=%d\n",
578692e5d73SJames Smart 				   scsi_status);
579692e5d73SJames Smart 		ocp->err = scsi_status;
580692e5d73SJames Smart 	}
581692e5d73SJames Smart 	efct_lio_io_printf(io, "seg_map_cnt=%d\n", ocp->seg_map_cnt);
582692e5d73SJames Smart 	if (ocp->seg_map_cnt) {
583692e5d73SJames Smart 		if (ocp->err == EFCT_SCSI_STATUS_GOOD &&
584692e5d73SJames Smart 		    ocp->cur_seg < ocp->seg_cnt) {
585692e5d73SJames Smart 			int rc;
586692e5d73SJames Smart 
587692e5d73SJames Smart 			efct_lio_io_printf(io, "continuing cmd at segm=%d\n",
588692e5d73SJames Smart 					   ocp->cur_seg);
589692e5d73SJames Smart 			if (ocp->ddir == DMA_TO_DEVICE)
590692e5d73SJames Smart 				rc = efct_lio_write_pending(&ocp->cmd);
591692e5d73SJames Smart 			else
592692e5d73SJames Smart 				rc = efct_lio_queue_data_in(&ocp->cmd);
593692e5d73SJames Smart 			if (!rc)
594692e5d73SJames Smart 				return 0;
595692e5d73SJames Smart 
596692e5d73SJames Smart 			ocp->err = EFCT_SCSI_STATUS_ERROR;
597692e5d73SJames Smart 			efct_lio_io_printf(io, "could not continue command\n");
598692e5d73SJames Smart 		}
599692e5d73SJames Smart 		efct_lio_sg_unmap(io);
600692e5d73SJames Smart 	}
601692e5d73SJames Smart 
602692e5d73SJames Smart 	if (io->tgt_io.aborting) {
603692e5d73SJames Smart 		efct_lio_io_printf(io, "IO done aborted\n");
604692e5d73SJames Smart 		return 0;
605692e5d73SJames Smart 	}
606692e5d73SJames Smart 
607692e5d73SJames Smart 	if (ocp->ddir == DMA_TO_DEVICE) {
608692e5d73SJames Smart 		efct_lio_io_printf(io, "Write done, trans_state=0x%x\n",
609692e5d73SJames Smart 				   io->tgt_io.cmd.transport_state);
610692e5d73SJames Smart 		if (scsi_status != EFCT_SCSI_STATUS_GOOD) {
611692e5d73SJames Smart 			transport_generic_request_failure(&io->tgt_io.cmd,
612692e5d73SJames Smart 					TCM_CHECK_CONDITION_ABORT_CMD);
613692e5d73SJames Smart 			efct_set_lio_io_state(io,
614692e5d73SJames Smart 				EFCT_LIO_STATE_TGT_GENERIC_REQ_FAILURE);
615692e5d73SJames Smart 		} else {
616692e5d73SJames Smart 			efct_set_lio_io_state(io,
617692e5d73SJames Smart 						EFCT_LIO_STATE_TGT_EXECUTE_CMD);
618692e5d73SJames Smart 			target_execute_cmd(&io->tgt_io.cmd);
619692e5d73SJames Smart 		}
620692e5d73SJames Smart 	} else {
621692e5d73SJames Smart 		efct_lio_send_resp(io, scsi_status, flags);
622692e5d73SJames Smart 	}
623692e5d73SJames Smart 	return 0;
624692e5d73SJames Smart }
625692e5d73SJames Smart 
626692e5d73SJames Smart static int
efct_lio_tmf_done(struct efct_io * io,enum efct_scsi_io_status scsi_status,u32 flags,void * arg)627692e5d73SJames Smart efct_lio_tmf_done(struct efct_io *io, enum efct_scsi_io_status scsi_status,
628692e5d73SJames Smart 		  u32 flags, void *arg)
629692e5d73SJames Smart {
630692e5d73SJames Smart 	efct_lio_tmfio_printf(io, "cmd=%p status=%d, flags=0x%x\n",
631692e5d73SJames Smart 			      &io->tgt_io.cmd, scsi_status, flags);
632692e5d73SJames Smart 
633692e5d73SJames Smart 	efct_set_lio_io_state(io, EFCT_LIO_STATE_TGT_GENERIC_FREE);
634692e5d73SJames Smart 	transport_generic_free_cmd(&io->tgt_io.cmd, 0);
635692e5d73SJames Smart 	return 0;
636692e5d73SJames Smart }
637692e5d73SJames Smart 
638692e5d73SJames Smart static int
efct_lio_null_tmf_done(struct efct_io * tmfio,enum efct_scsi_io_status scsi_status,u32 flags,void * arg)639692e5d73SJames Smart efct_lio_null_tmf_done(struct efct_io *tmfio,
640692e5d73SJames Smart 		       enum efct_scsi_io_status scsi_status,
641692e5d73SJames Smart 		      u32 flags, void *arg)
642692e5d73SJames Smart {
643692e5d73SJames Smart 	efct_lio_tmfio_printf(tmfio, "cmd=%p status=%d, flags=0x%x\n",
644692e5d73SJames Smart 			      &tmfio->tgt_io.cmd, scsi_status, flags);
645692e5d73SJames Smart 
646692e5d73SJames Smart 	/* free struct efct_io only, no active se_cmd */
647692e5d73SJames Smart 	efct_scsi_io_complete(tmfio);
648692e5d73SJames Smart 	return 0;
649692e5d73SJames Smart }
650692e5d73SJames Smart 
651692e5d73SJames Smart static int
efct_lio_queue_status(struct se_cmd * cmd)652692e5d73SJames Smart efct_lio_queue_status(struct se_cmd *cmd)
653692e5d73SJames Smart {
654692e5d73SJames Smart 	struct efct_scsi_cmd_resp rsp;
655692e5d73SJames Smart 	struct efct_scsi_tgt_io *ocp =
656692e5d73SJames Smart 		container_of(cmd, struct efct_scsi_tgt_io, cmd);
657692e5d73SJames Smart 	struct efct_io *io = container_of(ocp, struct efct_io, tgt_io);
658692e5d73SJames Smart 	int rc = 0;
659692e5d73SJames Smart 
660692e5d73SJames Smart 	efct_set_lio_io_state(io, EFCT_LIO_STATE_TFO_QUEUE_STATUS);
661692e5d73SJames Smart 	efct_lio_io_printf(io,
662692e5d73SJames Smart 		"status=0x%x trans_state=0x%x se_cmd_flags=0x%x sns_len=%d\n",
663692e5d73SJames Smart 		cmd->scsi_status, cmd->transport_state, cmd->se_cmd_flags,
664692e5d73SJames Smart 		cmd->scsi_sense_length);
665692e5d73SJames Smart 
666692e5d73SJames Smart 	memset(&rsp, 0, sizeof(rsp));
667692e5d73SJames Smart 	rsp.scsi_status = cmd->scsi_status;
668692e5d73SJames Smart 	rsp.sense_data = (u8 *)io->tgt_io.sense_buffer;
669692e5d73SJames Smart 	rsp.sense_data_length = cmd->scsi_sense_length;
670692e5d73SJames Smart 
671692e5d73SJames Smart 	/* Check for residual underrun or overrun, mark negitive value for
672692e5d73SJames Smart 	 * underrun to recognize in HW
673692e5d73SJames Smart 	 */
674692e5d73SJames Smart 	if (cmd->se_cmd_flags & SCF_OVERFLOW_BIT)
675692e5d73SJames Smart 		rsp.residual = -cmd->residual_count;
676692e5d73SJames Smart 	else if (cmd->se_cmd_flags & SCF_UNDERFLOW_BIT)
677692e5d73SJames Smart 		rsp.residual = cmd->residual_count;
678692e5d73SJames Smart 
679692e5d73SJames Smart 	rc = efct_scsi_send_resp(io, 0, &rsp, efct_lio_status_done, NULL);
680692e5d73SJames Smart 	efct_set_lio_io_state(io, EFCT_LIO_STATE_SCSI_SEND_RSP);
681692e5d73SJames Smart 	if (rc == 0)
682692e5d73SJames Smart 		ocp->rsp_sent = true;
683692e5d73SJames Smart 	return rc;
684692e5d73SJames Smart }
685692e5d73SJames Smart 
efct_lio_queue_tm_rsp(struct se_cmd * cmd)686692e5d73SJames Smart static void efct_lio_queue_tm_rsp(struct se_cmd *cmd)
687692e5d73SJames Smart {
688692e5d73SJames Smart 	struct efct_scsi_tgt_io *ocp =
689692e5d73SJames Smart 		container_of(cmd, struct efct_scsi_tgt_io, cmd);
690692e5d73SJames Smart 	struct efct_io *tmfio = container_of(ocp, struct efct_io, tgt_io);
691692e5d73SJames Smart 	struct se_tmr_req *se_tmr = cmd->se_tmr_req;
692692e5d73SJames Smart 	u8 rspcode;
693692e5d73SJames Smart 
694692e5d73SJames Smart 	efct_lio_tmfio_printf(tmfio, "cmd=%p function=0x%x tmr->response=%d\n",
695692e5d73SJames Smart 			      cmd, se_tmr->function, se_tmr->response);
696692e5d73SJames Smart 	switch (se_tmr->response) {
697692e5d73SJames Smart 	case TMR_FUNCTION_COMPLETE:
698692e5d73SJames Smart 		rspcode = EFCT_SCSI_TMF_FUNCTION_COMPLETE;
699692e5d73SJames Smart 		break;
700692e5d73SJames Smart 	case TMR_TASK_DOES_NOT_EXIST:
701692e5d73SJames Smart 		rspcode = EFCT_SCSI_TMF_FUNCTION_IO_NOT_FOUND;
702692e5d73SJames Smart 		break;
703692e5d73SJames Smart 	case TMR_LUN_DOES_NOT_EXIST:
704692e5d73SJames Smart 		rspcode = EFCT_SCSI_TMF_INCORRECT_LOGICAL_UNIT_NUMBER;
705692e5d73SJames Smart 		break;
706692e5d73SJames Smart 	case TMR_FUNCTION_REJECTED:
707692e5d73SJames Smart 	default:
708692e5d73SJames Smart 		rspcode = EFCT_SCSI_TMF_FUNCTION_REJECTED;
709692e5d73SJames Smart 		break;
710692e5d73SJames Smart 	}
711692e5d73SJames Smart 	efct_scsi_send_tmf_resp(tmfio, rspcode, NULL, efct_lio_tmf_done, NULL);
712692e5d73SJames Smart }
713692e5d73SJames Smart 
efct_find_wwpn(u64 wwpn)714692e5d73SJames Smart static struct efct *efct_find_wwpn(u64 wwpn)
715692e5d73SJames Smart {
716692e5d73SJames Smart 	struct efct *efct;
717692e5d73SJames Smart 
718692e5d73SJames Smart 	 /* Search for the HBA that has this WWPN */
719692e5d73SJames Smart 	list_for_each_entry(efct, &efct_devices, list_entry) {
720692e5d73SJames Smart 
721692e5d73SJames Smart 		if (wwpn == efct_get_wwpn(&efct->hw))
722692e5d73SJames Smart 			return efct;
723692e5d73SJames Smart 	}
724692e5d73SJames Smart 
725692e5d73SJames Smart 	return NULL;
726692e5d73SJames Smart }
727692e5d73SJames Smart 
728692e5d73SJames Smart static struct se_wwn *
efct_lio_make_nport(struct target_fabric_configfs * tf,struct config_group * group,const char * name)729692e5d73SJames Smart efct_lio_make_nport(struct target_fabric_configfs *tf,
730692e5d73SJames Smart 		    struct config_group *group, const char *name)
731692e5d73SJames Smart {
732692e5d73SJames Smart 	struct efct_lio_nport *lio_nport;
733692e5d73SJames Smart 	struct efct *efct;
734692e5d73SJames Smart 	int ret;
735692e5d73SJames Smart 	u64 wwpn;
736692e5d73SJames Smart 
737692e5d73SJames Smart 	ret = efct_lio_parse_wwn(name, &wwpn, 0);
738692e5d73SJames Smart 	if (ret)
739692e5d73SJames Smart 		return ERR_PTR(ret);
740692e5d73SJames Smart 
741692e5d73SJames Smart 	efct = efct_find_wwpn(wwpn);
742692e5d73SJames Smart 	if (!efct) {
743692e5d73SJames Smart 		pr_err("cannot find EFCT for base wwpn %s\n", name);
744692e5d73SJames Smart 		return ERR_PTR(-ENXIO);
745692e5d73SJames Smart 	}
746692e5d73SJames Smart 
747692e5d73SJames Smart 	lio_nport = kzalloc(sizeof(*lio_nport), GFP_KERNEL);
748692e5d73SJames Smart 	if (!lio_nport)
749692e5d73SJames Smart 		return ERR_PTR(-ENOMEM);
750692e5d73SJames Smart 
751692e5d73SJames Smart 	lio_nport->efct = efct;
752692e5d73SJames Smart 	lio_nport->wwpn = wwpn;
753692e5d73SJames Smart 	efct_format_wwn(lio_nport->wwpn_str, sizeof(lio_nport->wwpn_str),
754692e5d73SJames Smart 			"naa.", wwpn);
755692e5d73SJames Smart 	efct->tgt_efct.lio_nport = lio_nport;
756692e5d73SJames Smart 
757692e5d73SJames Smart 	return &lio_nport->nport_wwn;
758692e5d73SJames Smart }
759692e5d73SJames Smart 
760692e5d73SJames Smart static struct se_wwn *
efct_lio_npiv_make_nport(struct target_fabric_configfs * tf,struct config_group * group,const char * name)761692e5d73SJames Smart efct_lio_npiv_make_nport(struct target_fabric_configfs *tf,
762692e5d73SJames Smart 			 struct config_group *group, const char *name)
763692e5d73SJames Smart {
764692e5d73SJames Smart 	struct efct_lio_vport *lio_vport;
765692e5d73SJames Smart 	struct efct *efct;
766e71dd41eSColin Ian King 	int ret;
767692e5d73SJames Smart 	u64 p_wwpn, npiv_wwpn, npiv_wwnn;
768692e5d73SJames Smart 	char *p, *pbuf, tmp[128];
769692e5d73SJames Smart 	struct efct_lio_vport_list_t *vport_list;
770692e5d73SJames Smart 	struct fc_vport *new_fc_vport;
771692e5d73SJames Smart 	struct fc_vport_identifiers vport_id;
772692e5d73SJames Smart 	unsigned long flags = 0;
773692e5d73SJames Smart 
774692e5d73SJames Smart 	snprintf(tmp, sizeof(tmp), "%s", name);
775692e5d73SJames Smart 	pbuf = &tmp[0];
776692e5d73SJames Smart 
777692e5d73SJames Smart 	p = strsep(&pbuf, "@");
778692e5d73SJames Smart 
779692e5d73SJames Smart 	if (!p || !pbuf) {
780692e5d73SJames Smart 		pr_err("Unable to find separator operator(@)\n");
781692e5d73SJames Smart 		return ERR_PTR(-EINVAL);
782692e5d73SJames Smart 	}
783692e5d73SJames Smart 
784692e5d73SJames Smart 	ret = efct_lio_parse_wwn(p, &p_wwpn, 0);
785692e5d73SJames Smart 	if (ret)
786692e5d73SJames Smart 		return ERR_PTR(ret);
787692e5d73SJames Smart 
788692e5d73SJames Smart 	ret = efct_lio_parse_npiv_wwn(pbuf, strlen(pbuf), &npiv_wwpn,
789692e5d73SJames Smart 				      &npiv_wwnn);
790692e5d73SJames Smart 	if (ret)
791692e5d73SJames Smart 		return ERR_PTR(ret);
792692e5d73SJames Smart 
793692e5d73SJames Smart 	efct = efct_find_wwpn(p_wwpn);
794692e5d73SJames Smart 	if (!efct) {
795692e5d73SJames Smart 		pr_err("cannot find EFCT for base wwpn %s\n", name);
796692e5d73SJames Smart 		return ERR_PTR(-ENXIO);
797692e5d73SJames Smart 	}
798692e5d73SJames Smart 
799692e5d73SJames Smart 	lio_vport = kzalloc(sizeof(*lio_vport), GFP_KERNEL);
800692e5d73SJames Smart 	if (!lio_vport)
801692e5d73SJames Smart 		return ERR_PTR(-ENOMEM);
802692e5d73SJames Smart 
803692e5d73SJames Smart 	lio_vport->efct = efct;
804692e5d73SJames Smart 	lio_vport->wwpn = p_wwpn;
805692e5d73SJames Smart 	lio_vport->npiv_wwpn = npiv_wwpn;
806692e5d73SJames Smart 	lio_vport->npiv_wwnn = npiv_wwnn;
807692e5d73SJames Smart 
808692e5d73SJames Smart 	efct_format_wwn(lio_vport->wwpn_str, sizeof(lio_vport->wwpn_str),
809692e5d73SJames Smart 			"naa.", npiv_wwpn);
810692e5d73SJames Smart 
811692e5d73SJames Smart 	vport_list = kzalloc(sizeof(*vport_list), GFP_KERNEL);
812692e5d73SJames Smart 	if (!vport_list) {
813692e5d73SJames Smart 		kfree(lio_vport);
814692e5d73SJames Smart 		return ERR_PTR(-ENOMEM);
815692e5d73SJames Smart 	}
816692e5d73SJames Smart 
817692e5d73SJames Smart 	vport_list->lio_vport = lio_vport;
818692e5d73SJames Smart 
819692e5d73SJames Smart 	memset(&vport_id, 0, sizeof(vport_id));
820692e5d73SJames Smart 	vport_id.port_name = npiv_wwpn;
821692e5d73SJames Smart 	vport_id.node_name = npiv_wwnn;
822692e5d73SJames Smart 	vport_id.roles = FC_PORT_ROLE_FCP_INITIATOR;
823692e5d73SJames Smart 	vport_id.vport_type = FC_PORTTYPE_NPIV;
824692e5d73SJames Smart 	vport_id.disable = false;
825692e5d73SJames Smart 
826692e5d73SJames Smart 	new_fc_vport = fc_vport_create(efct->shost, 0, &vport_id);
827692e5d73SJames Smart 	if (!new_fc_vport) {
828692e5d73SJames Smart 		efc_log_err(efct, "fc_vport_create failed\n");
829692e5d73SJames Smart 		kfree(lio_vport);
830692e5d73SJames Smart 		kfree(vport_list);
831692e5d73SJames Smart 		return ERR_PTR(-ENOMEM);
832692e5d73SJames Smart 	}
833692e5d73SJames Smart 
834692e5d73SJames Smart 	lio_vport->fc_vport = new_fc_vport;
835f7c95d74SJames Smart 	spin_lock_irqsave(&efct->tgt_efct.efct_lio_lock, flags);
836f7c95d74SJames Smart 	INIT_LIST_HEAD(&vport_list->list_entry);
837f7c95d74SJames Smart 	list_add_tail(&vport_list->list_entry, &efct->tgt_efct.vport_list);
838f7c95d74SJames Smart 	spin_unlock_irqrestore(&efct->tgt_efct.efct_lio_lock, flags);
839692e5d73SJames Smart 
840692e5d73SJames Smart 	return &lio_vport->vport_wwn;
841692e5d73SJames Smart }
842692e5d73SJames Smart 
843692e5d73SJames Smart static void
efct_lio_drop_nport(struct se_wwn * wwn)844692e5d73SJames Smart efct_lio_drop_nport(struct se_wwn *wwn)
845692e5d73SJames Smart {
846692e5d73SJames Smart 	struct efct_lio_nport *lio_nport =
847692e5d73SJames Smart 		container_of(wwn, struct efct_lio_nport, nport_wwn);
848692e5d73SJames Smart 	struct efct *efct = lio_nport->efct;
849692e5d73SJames Smart 
850692e5d73SJames Smart 	/* only physical nport should exist, free lio_nport allocated
851692e5d73SJames Smart 	 * in efct_lio_make_nport.
852692e5d73SJames Smart 	 */
853692e5d73SJames Smart 	kfree(efct->tgt_efct.lio_nport);
854692e5d73SJames Smart 	efct->tgt_efct.lio_nport = NULL;
855692e5d73SJames Smart }
856692e5d73SJames Smart 
857692e5d73SJames Smart static void
efct_lio_npiv_drop_nport(struct se_wwn * wwn)858692e5d73SJames Smart efct_lio_npiv_drop_nport(struct se_wwn *wwn)
859692e5d73SJames Smart {
860692e5d73SJames Smart 	struct efct_lio_vport *lio_vport =
861692e5d73SJames Smart 		container_of(wwn, struct efct_lio_vport, vport_wwn);
862692e5d73SJames Smart 	struct efct_lio_vport_list_t *vport, *next_vport;
863692e5d73SJames Smart 	struct efct *efct = lio_vport->efct;
864692e5d73SJames Smart 	unsigned long flags = 0;
865692e5d73SJames Smart 
866692e5d73SJames Smart 	if (lio_vport->fc_vport)
867692e5d73SJames Smart 		fc_vport_terminate(lio_vport->fc_vport);
868692e5d73SJames Smart 
86945090742SJames Smart 	spin_lock_irqsave(&efct->tgt_efct.efct_lio_lock, flags);
87045090742SJames Smart 
871692e5d73SJames Smart 	list_for_each_entry_safe(vport, next_vport, &efct->tgt_efct.vport_list,
872692e5d73SJames Smart 				 list_entry) {
873692e5d73SJames Smart 		if (vport->lio_vport == lio_vport) {
874692e5d73SJames Smart 			list_del(&vport->list_entry);
875692e5d73SJames Smart 			kfree(vport->lio_vport);
876692e5d73SJames Smart 			kfree(vport);
877692e5d73SJames Smart 			break;
878692e5d73SJames Smart 		}
879692e5d73SJames Smart 	}
880692e5d73SJames Smart 	spin_unlock_irqrestore(&efct->tgt_efct.efct_lio_lock, flags);
881692e5d73SJames Smart }
882692e5d73SJames Smart 
883692e5d73SJames Smart static struct se_portal_group *
efct_lio_make_tpg(struct se_wwn * wwn,const char * name)884692e5d73SJames Smart efct_lio_make_tpg(struct se_wwn *wwn, const char *name)
885692e5d73SJames Smart {
886692e5d73SJames Smart 	struct efct_lio_nport *lio_nport =
887692e5d73SJames Smart 		container_of(wwn, struct efct_lio_nport, nport_wwn);
888692e5d73SJames Smart 	struct efct_lio_tpg *tpg;
889692e5d73SJames Smart 	struct efct *efct;
890692e5d73SJames Smart 	unsigned long n;
891692e5d73SJames Smart 	int ret;
892692e5d73SJames Smart 
893692e5d73SJames Smart 	if (strstr(name, "tpgt_") != name)
894692e5d73SJames Smart 		return ERR_PTR(-EINVAL);
895692e5d73SJames Smart 	if (kstrtoul(name + 5, 10, &n) || n > USHRT_MAX)
896692e5d73SJames Smart 		return ERR_PTR(-EINVAL);
897692e5d73SJames Smart 
898692e5d73SJames Smart 	tpg = kzalloc(sizeof(*tpg), GFP_KERNEL);
899692e5d73SJames Smart 	if (!tpg)
900692e5d73SJames Smart 		return ERR_PTR(-ENOMEM);
901692e5d73SJames Smart 
902692e5d73SJames Smart 	tpg->nport = lio_nport;
903692e5d73SJames Smart 	tpg->tpgt = n;
904692e5d73SJames Smart 	tpg->enabled = false;
905692e5d73SJames Smart 
906692e5d73SJames Smart 	tpg->tpg_attrib.generate_node_acls = 1;
907692e5d73SJames Smart 	tpg->tpg_attrib.demo_mode_write_protect = 1;
908692e5d73SJames Smart 	tpg->tpg_attrib.cache_dynamic_acls = 1;
909692e5d73SJames Smart 	tpg->tpg_attrib.demo_mode_login_only = 1;
910692e5d73SJames Smart 	tpg->tpg_attrib.session_deletion_wait = 1;
911692e5d73SJames Smart 
912692e5d73SJames Smart 	ret = core_tpg_register(wwn, &tpg->tpg, SCSI_PROTOCOL_FCP);
913692e5d73SJames Smart 	if (ret < 0) {
914692e5d73SJames Smart 		kfree(tpg);
915692e5d73SJames Smart 		return NULL;
916692e5d73SJames Smart 	}
917692e5d73SJames Smart 	efct = lio_nport->efct;
918692e5d73SJames Smart 	efct->tgt_efct.tpg = tpg;
919692e5d73SJames Smart 	efc_log_debug(efct, "create portal group %d\n", tpg->tpgt);
920692e5d73SJames Smart 
921692e5d73SJames Smart 	xa_init(&efct->lookup);
922692e5d73SJames Smart 	return &tpg->tpg;
923692e5d73SJames Smart }
924692e5d73SJames Smart 
925692e5d73SJames Smart static void
efct_lio_drop_tpg(struct se_portal_group * se_tpg)926692e5d73SJames Smart efct_lio_drop_tpg(struct se_portal_group *se_tpg)
927692e5d73SJames Smart {
928692e5d73SJames Smart 	struct efct_lio_tpg *tpg =
929692e5d73SJames Smart 		container_of(se_tpg, struct efct_lio_tpg, tpg);
930692e5d73SJames Smart 
931692e5d73SJames Smart 	struct efct *efct = tpg->nport->efct;
932692e5d73SJames Smart 
933692e5d73SJames Smart 	efc_log_debug(efct, "drop portal group %d\n", tpg->tpgt);
934692e5d73SJames Smart 	tpg->nport->efct->tgt_efct.tpg = NULL;
935692e5d73SJames Smart 	core_tpg_deregister(se_tpg);
936692e5d73SJames Smart 	xa_destroy(&efct->lookup);
937692e5d73SJames Smart 	kfree(tpg);
938692e5d73SJames Smart }
939692e5d73SJames Smart 
940692e5d73SJames Smart static struct se_portal_group *
efct_lio_npiv_make_tpg(struct se_wwn * wwn,const char * name)941692e5d73SJames Smart efct_lio_npiv_make_tpg(struct se_wwn *wwn, const char *name)
942692e5d73SJames Smart {
943692e5d73SJames Smart 	struct efct_lio_vport *lio_vport =
944692e5d73SJames Smart 		container_of(wwn, struct efct_lio_vport, vport_wwn);
945692e5d73SJames Smart 	struct efct_lio_tpg *tpg;
946692e5d73SJames Smart 	struct efct *efct;
947692e5d73SJames Smart 	unsigned long n;
948692e5d73SJames Smart 	int ret;
949692e5d73SJames Smart 
950692e5d73SJames Smart 	efct = lio_vport->efct;
951692e5d73SJames Smart 	if (strstr(name, "tpgt_") != name)
952692e5d73SJames Smart 		return ERR_PTR(-EINVAL);
953692e5d73SJames Smart 	if (kstrtoul(name + 5, 10, &n) || n > USHRT_MAX)
954692e5d73SJames Smart 		return ERR_PTR(-EINVAL);
955692e5d73SJames Smart 
956692e5d73SJames Smart 	if (n != 1) {
957692e5d73SJames Smart 		efc_log_err(efct, "Invalid tpgt index: %ld provided\n", n);
958692e5d73SJames Smart 		return ERR_PTR(-EINVAL);
959692e5d73SJames Smart 	}
960692e5d73SJames Smart 
961692e5d73SJames Smart 	tpg = kzalloc(sizeof(*tpg), GFP_KERNEL);
962692e5d73SJames Smart 	if (!tpg)
963692e5d73SJames Smart 		return ERR_PTR(-ENOMEM);
964692e5d73SJames Smart 
965692e5d73SJames Smart 	tpg->vport = lio_vport;
966692e5d73SJames Smart 	tpg->tpgt = n;
967692e5d73SJames Smart 	tpg->enabled = false;
968692e5d73SJames Smart 
969692e5d73SJames Smart 	tpg->tpg_attrib.generate_node_acls = 1;
970692e5d73SJames Smart 	tpg->tpg_attrib.demo_mode_write_protect = 1;
971692e5d73SJames Smart 	tpg->tpg_attrib.cache_dynamic_acls = 1;
972692e5d73SJames Smart 	tpg->tpg_attrib.demo_mode_login_only = 1;
973692e5d73SJames Smart 	tpg->tpg_attrib.session_deletion_wait = 1;
974692e5d73SJames Smart 
975692e5d73SJames Smart 	ret = core_tpg_register(wwn, &tpg->tpg, SCSI_PROTOCOL_FCP);
976692e5d73SJames Smart 
977692e5d73SJames Smart 	if (ret < 0) {
978692e5d73SJames Smart 		kfree(tpg);
979692e5d73SJames Smart 		return NULL;
980692e5d73SJames Smart 	}
981692e5d73SJames Smart 	lio_vport->tpg = tpg;
982692e5d73SJames Smart 	efc_log_debug(efct, "create vport portal group %d\n", tpg->tpgt);
983692e5d73SJames Smart 
984692e5d73SJames Smart 	return &tpg->tpg;
985692e5d73SJames Smart }
986692e5d73SJames Smart 
987692e5d73SJames Smart static void
efct_lio_npiv_drop_tpg(struct se_portal_group * se_tpg)988692e5d73SJames Smart efct_lio_npiv_drop_tpg(struct se_portal_group *se_tpg)
989692e5d73SJames Smart {
990692e5d73SJames Smart 	struct efct_lio_tpg *tpg =
991692e5d73SJames Smart 		container_of(se_tpg, struct efct_lio_tpg, tpg);
992692e5d73SJames Smart 
993692e5d73SJames Smart 	efc_log_debug(tpg->vport->efct, "drop npiv portal group %d\n",
994692e5d73SJames Smart 		       tpg->tpgt);
995692e5d73SJames Smart 	core_tpg_deregister(se_tpg);
996692e5d73SJames Smart 	kfree(tpg);
997692e5d73SJames Smart }
998692e5d73SJames Smart 
999692e5d73SJames Smart static int
efct_lio_init_nodeacl(struct se_node_acl * se_nacl,const char * name)1000692e5d73SJames Smart efct_lio_init_nodeacl(struct se_node_acl *se_nacl, const char *name)
1001692e5d73SJames Smart {
1002692e5d73SJames Smart 	struct efct_lio_nacl *nacl;
1003692e5d73SJames Smart 	u64 wwnn;
1004692e5d73SJames Smart 
1005692e5d73SJames Smart 	if (efct_lio_parse_wwn(name, &wwnn, 0) < 0)
1006692e5d73SJames Smart 		return -EINVAL;
1007692e5d73SJames Smart 
1008692e5d73SJames Smart 	nacl = container_of(se_nacl, struct efct_lio_nacl, se_node_acl);
1009692e5d73SJames Smart 	nacl->nport_wwnn = wwnn;
1010692e5d73SJames Smart 
1011692e5d73SJames Smart 	efct_format_wwn(nacl->nport_name, sizeof(nacl->nport_name), "", wwnn);
1012692e5d73SJames Smart 	return 0;
1013692e5d73SJames Smart }
1014692e5d73SJames Smart 
efct_lio_check_demo_mode_login_only(struct se_portal_group * stpg)1015692e5d73SJames Smart static int efct_lio_check_demo_mode_login_only(struct se_portal_group *stpg)
1016692e5d73SJames Smart {
1017692e5d73SJames Smart 	struct efct_lio_tpg *tpg = container_of(stpg, struct efct_lio_tpg, tpg);
1018692e5d73SJames Smart 
1019692e5d73SJames Smart 	return tpg->tpg_attrib.demo_mode_login_only;
1020692e5d73SJames Smart }
1021692e5d73SJames Smart 
1022692e5d73SJames Smart static int
efct_lio_npiv_check_demo_mode_login_only(struct se_portal_group * stpg)1023692e5d73SJames Smart efct_lio_npiv_check_demo_mode_login_only(struct se_portal_group *stpg)
1024692e5d73SJames Smart {
1025692e5d73SJames Smart 	struct efct_lio_tpg *tpg = container_of(stpg, struct efct_lio_tpg, tpg);
1026692e5d73SJames Smart 
1027692e5d73SJames Smart 	return tpg->tpg_attrib.demo_mode_login_only;
1028692e5d73SJames Smart }
1029692e5d73SJames Smart 
1030692e5d73SJames Smart static struct efct_lio_tpg *
efct_get_vport_tpg(struct efc_node * node)1031692e5d73SJames Smart efct_get_vport_tpg(struct efc_node *node)
1032692e5d73SJames Smart {
1033692e5d73SJames Smart 	struct efct *efct;
1034692e5d73SJames Smart 	u64 wwpn = node->nport->wwpn;
1035692e5d73SJames Smart 	struct efct_lio_vport_list_t *vport, *next;
1036692e5d73SJames Smart 	struct efct_lio_vport *lio_vport = NULL;
1037692e5d73SJames Smart 	struct efct_lio_tpg *tpg = NULL;
1038692e5d73SJames Smart 	unsigned long flags = 0;
1039692e5d73SJames Smart 
1040692e5d73SJames Smart 	efct = node->efc->base;
1041692e5d73SJames Smart 	spin_lock_irqsave(&efct->tgt_efct.efct_lio_lock, flags);
1042692e5d73SJames Smart 	list_for_each_entry_safe(vport, next, &efct->tgt_efct.vport_list,
1043692e5d73SJames Smart 				 list_entry) {
1044692e5d73SJames Smart 		lio_vport = vport->lio_vport;
1045692e5d73SJames Smart 		if (wwpn && lio_vport && lio_vport->npiv_wwpn == wwpn) {
1046692e5d73SJames Smart 			efc_log_debug(efct, "found tpg on vport\n");
1047692e5d73SJames Smart 			tpg = lio_vport->tpg;
1048692e5d73SJames Smart 			break;
1049692e5d73SJames Smart 		}
1050692e5d73SJames Smart 	}
1051692e5d73SJames Smart 	spin_unlock_irqrestore(&efct->tgt_efct.efct_lio_lock, flags);
1052692e5d73SJames Smart 	return tpg;
1053692e5d73SJames Smart }
1054692e5d73SJames Smart 
1055692e5d73SJames Smart static void
_efct_tgt_node_free(struct kref * arg)1056692e5d73SJames Smart _efct_tgt_node_free(struct kref *arg)
1057692e5d73SJames Smart {
1058692e5d73SJames Smart 	struct efct_node *tgt_node = container_of(arg, struct efct_node, ref);
1059692e5d73SJames Smart 	struct efc_node *node = tgt_node->node;
1060692e5d73SJames Smart 
1061692e5d73SJames Smart 	efc_scsi_del_initiator_complete(node->efc, node);
1062692e5d73SJames Smart 	kfree(tgt_node);
1063692e5d73SJames Smart }
1064692e5d73SJames Smart 
efct_session_cb(struct se_portal_group * se_tpg,struct se_session * se_sess,void * private)1065692e5d73SJames Smart static int efct_session_cb(struct se_portal_group *se_tpg,
1066692e5d73SJames Smart 			   struct se_session *se_sess, void *private)
1067692e5d73SJames Smart {
1068692e5d73SJames Smart 	struct efc_node *node = private;
1069692e5d73SJames Smart 	struct efct_node *tgt_node;
1070692e5d73SJames Smart 	struct efct *efct = node->efc->base;
1071692e5d73SJames Smart 
1072692e5d73SJames Smart 	tgt_node = kzalloc(sizeof(*tgt_node), GFP_KERNEL);
1073692e5d73SJames Smart 	if (!tgt_node)
1074692e5d73SJames Smart 		return -ENOMEM;
1075692e5d73SJames Smart 
1076692e5d73SJames Smart 	kref_init(&tgt_node->ref);
1077692e5d73SJames Smart 	tgt_node->release = _efct_tgt_node_free;
1078692e5d73SJames Smart 
1079692e5d73SJames Smart 	tgt_node->session = se_sess;
1080692e5d73SJames Smart 	node->tgt_node = tgt_node;
1081692e5d73SJames Smart 	tgt_node->efct = efct;
1082692e5d73SJames Smart 
1083692e5d73SJames Smart 	tgt_node->node = node;
1084692e5d73SJames Smart 
1085692e5d73SJames Smart 	tgt_node->node_fc_id = node->rnode.fc_id;
1086692e5d73SJames Smart 	tgt_node->port_fc_id = node->nport->fc_id;
1087692e5d73SJames Smart 	tgt_node->vpi = node->nport->indicator;
1088692e5d73SJames Smart 	tgt_node->rpi = node->rnode.indicator;
1089692e5d73SJames Smart 
1090692e5d73SJames Smart 	spin_lock_init(&tgt_node->active_ios_lock);
1091692e5d73SJames Smart 	INIT_LIST_HEAD(&tgt_node->active_ios);
1092692e5d73SJames Smart 
1093692e5d73SJames Smart 	return 0;
1094692e5d73SJames Smart }
1095692e5d73SJames Smart 
efct_scsi_tgt_new_device(struct efct * efct)1096692e5d73SJames Smart int efct_scsi_tgt_new_device(struct efct *efct)
1097692e5d73SJames Smart {
1098692e5d73SJames Smart 	u32 total_ios;
1099692e5d73SJames Smart 
1100692e5d73SJames Smart 	/* Get the max settings */
1101692e5d73SJames Smart 	efct->tgt_efct.max_sge = sli_get_max_sge(&efct->hw.sli);
1102692e5d73SJames Smart 	efct->tgt_efct.max_sgl = sli_get_max_sgl(&efct->hw.sli);
1103692e5d73SJames Smart 
1104692e5d73SJames Smart 	/* initialize IO watermark fields */
1105692e5d73SJames Smart 	atomic_set(&efct->tgt_efct.ios_in_use, 0);
1106692e5d73SJames Smart 	total_ios = efct->hw.config.n_io;
1107692e5d73SJames Smart 	efc_log_debug(efct, "total_ios=%d\n", total_ios);
1108692e5d73SJames Smart 	efct->tgt_efct.watermark_min =
1109692e5d73SJames Smart 			(total_ios * EFCT_WATERMARK_LOW_PCT) / 100;
1110692e5d73SJames Smart 	efct->tgt_efct.watermark_max =
1111692e5d73SJames Smart 			(total_ios * EFCT_WATERMARK_HIGH_PCT) / 100;
1112692e5d73SJames Smart 	atomic_set(&efct->tgt_efct.io_high_watermark,
1113692e5d73SJames Smart 		   efct->tgt_efct.watermark_max);
1114692e5d73SJames Smart 	atomic_set(&efct->tgt_efct.watermark_hit, 0);
1115692e5d73SJames Smart 	atomic_set(&efct->tgt_efct.initiator_count, 0);
1116692e5d73SJames Smart 
1117692e5d73SJames Smart 	lio_wq = create_singlethread_workqueue("efct_lio_worker");
1118692e5d73SJames Smart 	if (!lio_wq) {
1119692e5d73SJames Smart 		efc_log_err(efct, "workqueue create failed\n");
1120692e5d73SJames Smart 		return -EIO;
1121692e5d73SJames Smart 	}
1122692e5d73SJames Smart 
1123692e5d73SJames Smart 	spin_lock_init(&efct->tgt_efct.efct_lio_lock);
1124692e5d73SJames Smart 	INIT_LIST_HEAD(&efct->tgt_efct.vport_list);
1125692e5d73SJames Smart 
1126692e5d73SJames Smart 	return 0;
1127692e5d73SJames Smart }
1128692e5d73SJames Smart 
efct_scsi_tgt_del_device(struct efct * efct)1129692e5d73SJames Smart int efct_scsi_tgt_del_device(struct efct *efct)
1130692e5d73SJames Smart {
1131692e5d73SJames Smart 	flush_workqueue(lio_wq);
1132692e5d73SJames Smart 
1133692e5d73SJames Smart 	return 0;
1134692e5d73SJames Smart }
1135692e5d73SJames Smart 
1136692e5d73SJames Smart int
efct_scsi_tgt_new_nport(struct efc * efc,struct efc_nport * nport)1137692e5d73SJames Smart efct_scsi_tgt_new_nport(struct efc *efc, struct efc_nport *nport)
1138692e5d73SJames Smart {
1139692e5d73SJames Smart 	struct efct *efct = nport->efc->base;
1140692e5d73SJames Smart 
1141692e5d73SJames Smart 	efc_log_debug(efct, "New SPORT: %s bound to %s\n", nport->display_name,
1142692e5d73SJames Smart 		       efct->tgt_efct.lio_nport->wwpn_str);
1143692e5d73SJames Smart 
1144692e5d73SJames Smart 	return 0;
1145692e5d73SJames Smart }
1146692e5d73SJames Smart 
1147692e5d73SJames Smart void
efct_scsi_tgt_del_nport(struct efc * efc,struct efc_nport * nport)1148692e5d73SJames Smart efct_scsi_tgt_del_nport(struct efc *efc, struct efc_nport *nport)
1149692e5d73SJames Smart {
1150692e5d73SJames Smart 	efc_log_debug(efc, "Del SPORT: %s\n", nport->display_name);
1151692e5d73SJames Smart }
1152692e5d73SJames Smart 
efct_lio_setup_session(struct work_struct * work)1153692e5d73SJames Smart static void efct_lio_setup_session(struct work_struct *work)
1154692e5d73SJames Smart {
1155692e5d73SJames Smart 	struct efct_lio_wq_data *wq_data =
1156692e5d73SJames Smart 		container_of(work, struct efct_lio_wq_data, work);
1157692e5d73SJames Smart 	struct efct *efct = wq_data->efct;
1158692e5d73SJames Smart 	struct efc_node *node = wq_data->ptr;
1159692e5d73SJames Smart 	char wwpn[WWN_NAME_LEN];
1160692e5d73SJames Smart 	struct efct_lio_tpg *tpg;
1161692e5d73SJames Smart 	struct efct_node *tgt_node;
1162692e5d73SJames Smart 	struct se_portal_group *se_tpg;
1163692e5d73SJames Smart 	struct se_session *se_sess;
1164692e5d73SJames Smart 	int watermark;
1165692e5d73SJames Smart 	int ini_count;
1166692e5d73SJames Smart 	u64 id;
1167692e5d73SJames Smart 
1168692e5d73SJames Smart 	/* Check to see if it's belongs to vport,
1169692e5d73SJames Smart 	 * if not get physical port
1170692e5d73SJames Smart 	 */
1171692e5d73SJames Smart 	tpg = efct_get_vport_tpg(node);
1172692e5d73SJames Smart 	if (tpg) {
1173692e5d73SJames Smart 		se_tpg = &tpg->tpg;
1174692e5d73SJames Smart 	} else if (efct->tgt_efct.tpg) {
1175692e5d73SJames Smart 		tpg = efct->tgt_efct.tpg;
1176692e5d73SJames Smart 		se_tpg = &tpg->tpg;
1177692e5d73SJames Smart 	} else {
1178692e5d73SJames Smart 		efc_log_err(efct, "failed to init session\n");
1179692e5d73SJames Smart 		return;
1180692e5d73SJames Smart 	}
1181692e5d73SJames Smart 
1182692e5d73SJames Smart 	/*
1183692e5d73SJames Smart 	 * Format the FCP Initiator port_name into colon
1184692e5d73SJames Smart 	 * separated values to match the format by our explicit
1185692e5d73SJames Smart 	 * ConfigFS NodeACLs.
1186692e5d73SJames Smart 	 */
1187692e5d73SJames Smart 	efct_format_wwn(wwpn, sizeof(wwpn), "",	efc_node_get_wwpn(node));
1188692e5d73SJames Smart 
1189692e5d73SJames Smart 	se_sess = target_setup_session(se_tpg, 0, 0, TARGET_PROT_NORMAL, wwpn,
1190692e5d73SJames Smart 				       node, efct_session_cb);
1191692e5d73SJames Smart 	if (IS_ERR(se_sess)) {
1192692e5d73SJames Smart 		efc_log_err(efct, "failed to setup session\n");
1193692e5d73SJames Smart 		kfree(wq_data);
1194692e5d73SJames Smart 		efc_scsi_sess_reg_complete(node, -EIO);
1195692e5d73SJames Smart 		return;
1196692e5d73SJames Smart 	}
1197692e5d73SJames Smart 
1198692e5d73SJames Smart 	tgt_node = node->tgt_node;
1199692e5d73SJames Smart 	id = (u64) tgt_node->port_fc_id << 32 | tgt_node->node_fc_id;
1200692e5d73SJames Smart 
1201a2550361SNathan Chancellor 	efc_log_debug(efct, "new initiator sess=%p node=%p id: %llx\n",
1202a2550361SNathan Chancellor 		      se_sess, node, id);
1203a2550361SNathan Chancellor 
1204692e5d73SJames Smart 	if (xa_err(xa_store(&efct->lookup, id, tgt_node, GFP_KERNEL)))
1205692e5d73SJames Smart 		efc_log_err(efct, "Node lookup store failed\n");
1206692e5d73SJames Smart 
1207692e5d73SJames Smart 	efc_scsi_sess_reg_complete(node, 0);
1208692e5d73SJames Smart 
1209692e5d73SJames Smart 	/* update IO watermark: increment initiator count */
1210692e5d73SJames Smart 	ini_count = atomic_add_return(1, &efct->tgt_efct.initiator_count);
1211692e5d73SJames Smart 	watermark = efct->tgt_efct.watermark_max -
1212692e5d73SJames Smart 		    ini_count * EFCT_IO_WATERMARK_PER_INITIATOR;
1213692e5d73SJames Smart 	watermark = (efct->tgt_efct.watermark_min > watermark) ?
1214692e5d73SJames Smart 			efct->tgt_efct.watermark_min : watermark;
1215692e5d73SJames Smart 	atomic_set(&efct->tgt_efct.io_high_watermark, watermark);
1216692e5d73SJames Smart 
1217692e5d73SJames Smart 	kfree(wq_data);
1218692e5d73SJames Smart }
1219692e5d73SJames Smart 
efct_scsi_new_initiator(struct efc * efc,struct efc_node * node)1220692e5d73SJames Smart int efct_scsi_new_initiator(struct efc *efc, struct efc_node *node)
1221692e5d73SJames Smart {
1222692e5d73SJames Smart 	struct efct *efct = node->efc->base;
1223692e5d73SJames Smart 	struct efct_lio_wq_data *wq_data;
1224692e5d73SJames Smart 
1225692e5d73SJames Smart 	/*
1226692e5d73SJames Smart 	 * Since LIO only supports initiator validation at thread level,
1227692e5d73SJames Smart 	 * we are open minded and accept all callers.
1228692e5d73SJames Smart 	 */
1229692e5d73SJames Smart 	wq_data = kzalloc(sizeof(*wq_data), GFP_ATOMIC);
1230692e5d73SJames Smart 	if (!wq_data)
1231692e5d73SJames Smart 		return -ENOMEM;
1232692e5d73SJames Smart 
1233692e5d73SJames Smart 	wq_data->ptr = node;
1234692e5d73SJames Smart 	wq_data->efct = efct;
1235692e5d73SJames Smart 	INIT_WORK(&wq_data->work, efct_lio_setup_session);
1236692e5d73SJames Smart 	queue_work(lio_wq, &wq_data->work);
1237692e5d73SJames Smart 	return EFC_SCSI_CALL_ASYNC;
1238692e5d73SJames Smart }
1239692e5d73SJames Smart 
efct_lio_remove_session(struct work_struct * work)1240692e5d73SJames Smart static void efct_lio_remove_session(struct work_struct *work)
1241692e5d73SJames Smart {
1242692e5d73SJames Smart 	struct efct_lio_wq_data *wq_data =
1243692e5d73SJames Smart 		container_of(work, struct efct_lio_wq_data, work);
1244692e5d73SJames Smart 	struct efct *efct = wq_data->efct;
1245692e5d73SJames Smart 	struct efc_node *node = wq_data->ptr;
1246692e5d73SJames Smart 	struct efct_node *tgt_node;
1247692e5d73SJames Smart 	struct se_session *se_sess;
1248692e5d73SJames Smart 
1249692e5d73SJames Smart 	tgt_node = node->tgt_node;
1250692e5d73SJames Smart 	if (!tgt_node) {
1251692e5d73SJames Smart 		/* base driver has sent back-to-back requests
1252692e5d73SJames Smart 		 * to unreg session with no intervening
1253692e5d73SJames Smart 		 * register
1254692e5d73SJames Smart 		 */
1255692e5d73SJames Smart 		efc_log_err(efct, "unreg session for NULL session\n");
1256692e5d73SJames Smart 		efc_scsi_del_initiator_complete(node->efc, node);
1257692e5d73SJames Smart 		return;
1258692e5d73SJames Smart 	}
1259692e5d73SJames Smart 
1260692e5d73SJames Smart 	se_sess = tgt_node->session;
1261692e5d73SJames Smart 	efc_log_debug(efct, "unreg session se_sess=%p node=%p\n",
1262692e5d73SJames Smart 		       se_sess, node);
1263692e5d73SJames Smart 
1264692e5d73SJames Smart 	/* first flag all session commands to complete */
1265692e5d73SJames Smart 	target_stop_session(se_sess);
1266692e5d73SJames Smart 
1267692e5d73SJames Smart 	/* now wait for session commands to complete */
1268692e5d73SJames Smart 	target_wait_for_sess_cmds(se_sess);
1269692e5d73SJames Smart 	target_remove_session(se_sess);
1270692e5d73SJames Smart 	tgt_node->session = NULL;
1271692e5d73SJames Smart 	node->tgt_node = NULL;
1272692e5d73SJames Smart 	kref_put(&tgt_node->ref, tgt_node->release);
1273692e5d73SJames Smart 
1274692e5d73SJames Smart 	kfree(wq_data);
1275692e5d73SJames Smart }
1276692e5d73SJames Smart 
efct_scsi_del_initiator(struct efc * efc,struct efc_node * node,int reason)1277692e5d73SJames Smart int efct_scsi_del_initiator(struct efc *efc, struct efc_node *node, int reason)
1278692e5d73SJames Smart {
1279692e5d73SJames Smart 	struct efct *efct = node->efc->base;
1280692e5d73SJames Smart 	struct efct_node *tgt_node = node->tgt_node;
1281692e5d73SJames Smart 	struct efct_lio_wq_data *wq_data;
1282692e5d73SJames Smart 	int watermark;
1283692e5d73SJames Smart 	int ini_count;
1284692e5d73SJames Smart 	u64 id;
1285692e5d73SJames Smart 
1286692e5d73SJames Smart 	if (reason == EFCT_SCSI_INITIATOR_MISSING)
1287692e5d73SJames Smart 		return EFC_SCSI_CALL_COMPLETE;
1288692e5d73SJames Smart 
1289692e5d73SJames Smart 	if (!tgt_node) {
1290692e5d73SJames Smart 		efc_log_err(efct, "tgt_node is NULL\n");
1291692e5d73SJames Smart 		return -EIO;
1292692e5d73SJames Smart 	}
1293692e5d73SJames Smart 
1294692e5d73SJames Smart 	wq_data = kzalloc(sizeof(*wq_data), GFP_ATOMIC);
1295692e5d73SJames Smart 	if (!wq_data)
1296692e5d73SJames Smart 		return -ENOMEM;
1297692e5d73SJames Smart 
1298692e5d73SJames Smart 	id = (u64) tgt_node->port_fc_id << 32 | tgt_node->node_fc_id;
1299692e5d73SJames Smart 	xa_erase(&efct->lookup, id);
1300692e5d73SJames Smart 
1301692e5d73SJames Smart 	wq_data->ptr = node;
1302692e5d73SJames Smart 	wq_data->efct = efct;
1303692e5d73SJames Smart 	INIT_WORK(&wq_data->work, efct_lio_remove_session);
1304692e5d73SJames Smart 	queue_work(lio_wq, &wq_data->work);
1305692e5d73SJames Smart 
1306692e5d73SJames Smart 	/*
1307692e5d73SJames Smart 	 * update IO watermark: decrement initiator count
1308692e5d73SJames Smart 	 */
1309692e5d73SJames Smart 	ini_count = atomic_sub_return(1, &efct->tgt_efct.initiator_count);
1310692e5d73SJames Smart 
1311692e5d73SJames Smart 	watermark = efct->tgt_efct.watermark_max -
1312692e5d73SJames Smart 		    ini_count * EFCT_IO_WATERMARK_PER_INITIATOR;
1313692e5d73SJames Smart 	watermark = (efct->tgt_efct.watermark_min > watermark) ?
1314692e5d73SJames Smart 			efct->tgt_efct.watermark_min : watermark;
1315692e5d73SJames Smart 	atomic_set(&efct->tgt_efct.io_high_watermark, watermark);
1316692e5d73SJames Smart 
1317692e5d73SJames Smart 	return EFC_SCSI_CALL_ASYNC;
1318692e5d73SJames Smart }
1319692e5d73SJames Smart 
efct_scsi_recv_cmd(struct efct_io * io,uint64_t lun,u8 * cdb,u32 cdb_len,u32 flags)1320692e5d73SJames Smart void efct_scsi_recv_cmd(struct efct_io *io, uint64_t lun, u8 *cdb,
1321692e5d73SJames Smart 		       u32 cdb_len, u32 flags)
1322692e5d73SJames Smart {
1323692e5d73SJames Smart 	struct efct_scsi_tgt_io *ocp = &io->tgt_io;
1324692e5d73SJames Smart 	struct se_cmd *se_cmd = &io->tgt_io.cmd;
1325692e5d73SJames Smart 	struct efct *efct = io->efct;
1326692e5d73SJames Smart 	char *ddir;
1327692e5d73SJames Smart 	struct efct_node *tgt_node;
1328692e5d73SJames Smart 	struct se_session *se_sess;
1329692e5d73SJames Smart 	int rc = 0;
1330692e5d73SJames Smart 
1331692e5d73SJames Smart 	memset(ocp, 0, sizeof(struct efct_scsi_tgt_io));
1332692e5d73SJames Smart 	efct_set_lio_io_state(io, EFCT_LIO_STATE_SCSI_RECV_CMD);
1333692e5d73SJames Smart 	atomic_add_return(1, &efct->tgt_efct.ios_in_use);
1334692e5d73SJames Smart 
1335692e5d73SJames Smart 	/* set target timeout */
1336692e5d73SJames Smart 	io->timeout = efct->target_io_timer_sec;
1337692e5d73SJames Smart 
1338692e5d73SJames Smart 	if (flags & EFCT_SCSI_CMD_SIMPLE)
1339692e5d73SJames Smart 		ocp->task_attr = TCM_SIMPLE_TAG;
1340692e5d73SJames Smart 	else if (flags & EFCT_SCSI_CMD_HEAD_OF_QUEUE)
1341692e5d73SJames Smart 		ocp->task_attr = TCM_HEAD_TAG;
1342692e5d73SJames Smart 	else if (flags & EFCT_SCSI_CMD_ORDERED)
1343692e5d73SJames Smart 		ocp->task_attr = TCM_ORDERED_TAG;
1344692e5d73SJames Smart 	else if (flags & EFCT_SCSI_CMD_ACA)
1345692e5d73SJames Smart 		ocp->task_attr = TCM_ACA_TAG;
1346692e5d73SJames Smart 
1347692e5d73SJames Smart 	switch (flags & (EFCT_SCSI_CMD_DIR_IN | EFCT_SCSI_CMD_DIR_OUT)) {
1348692e5d73SJames Smart 	case EFCT_SCSI_CMD_DIR_IN:
1349692e5d73SJames Smart 		ddir = "FROM_INITIATOR";
1350692e5d73SJames Smart 		ocp->ddir = DMA_TO_DEVICE;
1351692e5d73SJames Smart 		break;
1352692e5d73SJames Smart 	case EFCT_SCSI_CMD_DIR_OUT:
1353692e5d73SJames Smart 		ddir = "TO_INITIATOR";
1354692e5d73SJames Smart 		ocp->ddir = DMA_FROM_DEVICE;
1355692e5d73SJames Smart 		break;
1356692e5d73SJames Smart 	case EFCT_SCSI_CMD_DIR_IN | EFCT_SCSI_CMD_DIR_OUT:
1357692e5d73SJames Smart 		ddir = "BIDIR";
1358692e5d73SJames Smart 		ocp->ddir = DMA_BIDIRECTIONAL;
1359692e5d73SJames Smart 		break;
1360692e5d73SJames Smart 	default:
1361692e5d73SJames Smart 		ddir = "NONE";
1362692e5d73SJames Smart 		ocp->ddir = DMA_NONE;
1363692e5d73SJames Smart 		break;
1364692e5d73SJames Smart 	}
1365692e5d73SJames Smart 
1366692e5d73SJames Smart 	ocp->lun = lun;
1367692e5d73SJames Smart 	efct_lio_io_printf(io, "new cmd=0x%x ddir=%s dl=%u\n",
1368692e5d73SJames Smart 			   cdb[0], ddir, io->exp_xfer_len);
1369692e5d73SJames Smart 
1370692e5d73SJames Smart 	tgt_node = io->node;
1371692e5d73SJames Smart 	se_sess = tgt_node->session;
1372692e5d73SJames Smart 	if (!se_sess) {
1373692e5d73SJames Smart 		efc_log_err(efct, "No session found to submit IO se_cmd: %p\n",
1374692e5d73SJames Smart 			    &ocp->cmd);
1375692e5d73SJames Smart 		efct_scsi_io_free(io);
1376692e5d73SJames Smart 		return;
1377692e5d73SJames Smart 	}
1378692e5d73SJames Smart 
1379692e5d73SJames Smart 	efct_set_lio_io_state(io, EFCT_LIO_STATE_TGT_SUBMIT_CMD);
1380692e5d73SJames Smart 	rc = target_init_cmd(se_cmd, se_sess, &io->tgt_io.sense_buffer[0],
1381692e5d73SJames Smart 			     ocp->lun, io->exp_xfer_len, ocp->task_attr,
1382692e5d73SJames Smart 			     ocp->ddir, TARGET_SCF_ACK_KREF);
1383692e5d73SJames Smart 	if (rc) {
1384692e5d73SJames Smart 		efc_log_err(efct, "failed to init cmd se_cmd: %p\n", se_cmd);
1385692e5d73SJames Smart 		efct_scsi_io_free(io);
1386692e5d73SJames Smart 		return;
1387692e5d73SJames Smart 	}
1388692e5d73SJames Smart 
1389692e5d73SJames Smart 	if (target_submit_prep(se_cmd, cdb, NULL, 0, NULL, 0,
1390692e5d73SJames Smart 				NULL, 0, GFP_ATOMIC))
1391692e5d73SJames Smart 		return;
1392692e5d73SJames Smart 
1393692e5d73SJames Smart 	target_submit(se_cmd);
1394692e5d73SJames Smart }
1395692e5d73SJames Smart 
1396692e5d73SJames Smart int
efct_scsi_recv_tmf(struct efct_io * tmfio,u32 lun,enum efct_scsi_tmf_cmd cmd,struct efct_io * io_to_abort,u32 flags)1397692e5d73SJames Smart efct_scsi_recv_tmf(struct efct_io *tmfio, u32 lun, enum efct_scsi_tmf_cmd cmd,
1398692e5d73SJames Smart 		   struct efct_io *io_to_abort, u32 flags)
1399692e5d73SJames Smart {
1400692e5d73SJames Smart 	unsigned char tmr_func;
1401692e5d73SJames Smart 	struct efct *efct = tmfio->efct;
1402692e5d73SJames Smart 	struct efct_scsi_tgt_io *ocp = &tmfio->tgt_io;
1403692e5d73SJames Smart 	struct efct_node *tgt_node;
1404692e5d73SJames Smart 	struct se_session *se_sess;
1405692e5d73SJames Smart 	int rc;
1406692e5d73SJames Smart 
1407692e5d73SJames Smart 	memset(ocp, 0, sizeof(struct efct_scsi_tgt_io));
1408692e5d73SJames Smart 	efct_set_lio_io_state(tmfio, EFCT_LIO_STATE_SCSI_RECV_TMF);
1409692e5d73SJames Smart 	atomic_add_return(1, &efct->tgt_efct.ios_in_use);
1410692e5d73SJames Smart 	efct_lio_tmfio_printf(tmfio, "%s: new tmf %x lun=%u\n",
1411692e5d73SJames Smart 			      tmfio->display_name, cmd, lun);
1412692e5d73SJames Smart 
1413692e5d73SJames Smart 	switch (cmd) {
1414692e5d73SJames Smart 	case EFCT_SCSI_TMF_ABORT_TASK:
1415692e5d73SJames Smart 		tmr_func = TMR_ABORT_TASK;
1416692e5d73SJames Smart 		break;
1417692e5d73SJames Smart 	case EFCT_SCSI_TMF_ABORT_TASK_SET:
1418692e5d73SJames Smart 		tmr_func = TMR_ABORT_TASK_SET;
1419692e5d73SJames Smart 		break;
1420692e5d73SJames Smart 	case EFCT_SCSI_TMF_CLEAR_TASK_SET:
1421692e5d73SJames Smart 		tmr_func = TMR_CLEAR_TASK_SET;
1422692e5d73SJames Smart 		break;
1423692e5d73SJames Smart 	case EFCT_SCSI_TMF_LOGICAL_UNIT_RESET:
1424692e5d73SJames Smart 		tmr_func = TMR_LUN_RESET;
1425692e5d73SJames Smart 		break;
1426692e5d73SJames Smart 	case EFCT_SCSI_TMF_CLEAR_ACA:
1427692e5d73SJames Smart 		tmr_func = TMR_CLEAR_ACA;
1428692e5d73SJames Smart 		break;
1429692e5d73SJames Smart 	case EFCT_SCSI_TMF_TARGET_RESET:
1430692e5d73SJames Smart 		tmr_func = TMR_TARGET_WARM_RESET;
1431692e5d73SJames Smart 		break;
1432692e5d73SJames Smart 	case EFCT_SCSI_TMF_QUERY_ASYNCHRONOUS_EVENT:
1433692e5d73SJames Smart 	case EFCT_SCSI_TMF_QUERY_TASK_SET:
1434692e5d73SJames Smart 	default:
1435692e5d73SJames Smart 		goto tmf_fail;
1436692e5d73SJames Smart 	}
1437692e5d73SJames Smart 
1438692e5d73SJames Smart 	tmfio->tgt_io.tmf = tmr_func;
1439692e5d73SJames Smart 	tmfio->tgt_io.lun = lun;
1440692e5d73SJames Smart 	tmfio->tgt_io.io_to_abort = io_to_abort;
1441692e5d73SJames Smart 
1442692e5d73SJames Smart 	tgt_node = tmfio->node;
1443692e5d73SJames Smart 
1444692e5d73SJames Smart 	se_sess = tgt_node->session;
1445692e5d73SJames Smart 	if (!se_sess)
1446692e5d73SJames Smart 		return 0;
1447692e5d73SJames Smart 
1448692e5d73SJames Smart 	rc = target_submit_tmr(&ocp->cmd, se_sess, NULL, lun, ocp, tmr_func,
1449692e5d73SJames Smart 			GFP_ATOMIC, tmfio->init_task_tag, TARGET_SCF_ACK_KREF);
1450692e5d73SJames Smart 
1451692e5d73SJames Smart 	efct_set_lio_io_state(tmfio, EFCT_LIO_STATE_TGT_SUBMIT_TMR);
1452692e5d73SJames Smart 	if (rc)
1453692e5d73SJames Smart 		goto tmf_fail;
1454692e5d73SJames Smart 
1455692e5d73SJames Smart 	return 0;
1456692e5d73SJames Smart 
1457692e5d73SJames Smart tmf_fail:
1458692e5d73SJames Smart 	efct_scsi_send_tmf_resp(tmfio, EFCT_SCSI_TMF_FUNCTION_REJECTED,
1459692e5d73SJames Smart 				NULL, efct_lio_null_tmf_done, NULL);
1460692e5d73SJames Smart 	return 0;
1461692e5d73SJames Smart }
1462692e5d73SJames Smart 
1463692e5d73SJames Smart /* Start items for efct_lio_tpg_attrib_cit */
1464692e5d73SJames Smart 
1465692e5d73SJames Smart #define DEF_EFCT_TPG_ATTRIB(name)					  \
1466692e5d73SJames Smart 									  \
1467692e5d73SJames Smart static ssize_t efct_lio_tpg_attrib_##name##_show(			  \
1468692e5d73SJames Smart 		struct config_item *item, char *page)			  \
1469692e5d73SJames Smart {									  \
1470692e5d73SJames Smart 	struct se_portal_group *se_tpg = to_tpg(item);			  \
1471692e5d73SJames Smart 	struct efct_lio_tpg *tpg = container_of(se_tpg,			  \
1472692e5d73SJames Smart 			struct efct_lio_tpg, tpg);			  \
1473692e5d73SJames Smart 									  \
1474692e5d73SJames Smart 	return sprintf(page, "%u\n", tpg->tpg_attrib.name);		  \
1475692e5d73SJames Smart }									  \
1476692e5d73SJames Smart 									  \
1477692e5d73SJames Smart static ssize_t efct_lio_tpg_attrib_##name##_store(			  \
1478692e5d73SJames Smart 		struct config_item *item, const char *page, size_t count) \
1479692e5d73SJames Smart {									  \
1480692e5d73SJames Smart 	struct se_portal_group *se_tpg = to_tpg(item);			  \
1481692e5d73SJames Smart 	struct efct_lio_tpg *tpg = container_of(se_tpg,			  \
1482692e5d73SJames Smart 					struct efct_lio_tpg, tpg);	  \
1483692e5d73SJames Smart 	struct efct_lio_tpg_attrib *a = &tpg->tpg_attrib;		  \
1484692e5d73SJames Smart 	unsigned long val;						  \
1485692e5d73SJames Smart 	int ret;							  \
1486692e5d73SJames Smart 									  \
1487692e5d73SJames Smart 	ret = kstrtoul(page, 0, &val);					  \
1488692e5d73SJames Smart 	if (ret < 0) {							  \
1489692e5d73SJames Smart 		pr_err("kstrtoul() failed with ret: %d\n", ret);	  \
1490692e5d73SJames Smart 		return ret;						  \
1491692e5d73SJames Smart 	}								  \
1492692e5d73SJames Smart 									  \
1493692e5d73SJames Smart 	if (val != 0 && val != 1) {					  \
1494692e5d73SJames Smart 		pr_err("Illegal boolean value %lu\n", val);		  \
1495692e5d73SJames Smart 		return -EINVAL;						  \
1496692e5d73SJames Smart 	}								  \
1497692e5d73SJames Smart 									  \
1498692e5d73SJames Smart 	a->name = val;							  \
1499692e5d73SJames Smart 									  \
1500692e5d73SJames Smart 	return count;							  \
1501692e5d73SJames Smart }									  \
1502692e5d73SJames Smart CONFIGFS_ATTR(efct_lio_tpg_attrib_, name)
1503692e5d73SJames Smart 
1504692e5d73SJames Smart DEF_EFCT_TPG_ATTRIB(generate_node_acls);
1505692e5d73SJames Smart DEF_EFCT_TPG_ATTRIB(cache_dynamic_acls);
1506692e5d73SJames Smart DEF_EFCT_TPG_ATTRIB(demo_mode_write_protect);
1507692e5d73SJames Smart DEF_EFCT_TPG_ATTRIB(prod_mode_write_protect);
1508692e5d73SJames Smart DEF_EFCT_TPG_ATTRIB(demo_mode_login_only);
1509692e5d73SJames Smart DEF_EFCT_TPG_ATTRIB(session_deletion_wait);
1510692e5d73SJames Smart 
1511692e5d73SJames Smart static struct configfs_attribute *efct_lio_tpg_attrib_attrs[] = {
1512692e5d73SJames Smart 	&efct_lio_tpg_attrib_attr_generate_node_acls,
1513692e5d73SJames Smart 	&efct_lio_tpg_attrib_attr_cache_dynamic_acls,
1514692e5d73SJames Smart 	&efct_lio_tpg_attrib_attr_demo_mode_write_protect,
1515692e5d73SJames Smart 	&efct_lio_tpg_attrib_attr_prod_mode_write_protect,
1516692e5d73SJames Smart 	&efct_lio_tpg_attrib_attr_demo_mode_login_only,
1517692e5d73SJames Smart 	&efct_lio_tpg_attrib_attr_session_deletion_wait,
1518692e5d73SJames Smart 	NULL,
1519692e5d73SJames Smart };
1520692e5d73SJames Smart 
1521692e5d73SJames Smart #define DEF_EFCT_NPIV_TPG_ATTRIB(name)					   \
1522692e5d73SJames Smart 									   \
1523692e5d73SJames Smart static ssize_t efct_lio_npiv_tpg_attrib_##name##_show(			   \
1524692e5d73SJames Smart 		struct config_item *item, char *page)			   \
1525692e5d73SJames Smart {									   \
1526692e5d73SJames Smart 	struct se_portal_group *se_tpg = to_tpg(item);			   \
1527692e5d73SJames Smart 	struct efct_lio_tpg *tpg = container_of(se_tpg,			   \
1528692e5d73SJames Smart 			struct efct_lio_tpg, tpg);			   \
1529692e5d73SJames Smart 									   \
1530692e5d73SJames Smart 	return sprintf(page, "%u\n", tpg->tpg_attrib.name);		   \
1531692e5d73SJames Smart }									   \
1532692e5d73SJames Smart 									   \
1533692e5d73SJames Smart static ssize_t efct_lio_npiv_tpg_attrib_##name##_store(			   \
1534692e5d73SJames Smart 		struct config_item *item, const char *page, size_t count)  \
1535692e5d73SJames Smart {									   \
1536692e5d73SJames Smart 	struct se_portal_group *se_tpg = to_tpg(item);			   \
1537692e5d73SJames Smart 	struct efct_lio_tpg *tpg = container_of(se_tpg,			   \
1538692e5d73SJames Smart 			struct efct_lio_tpg, tpg);			   \
1539692e5d73SJames Smart 	struct efct_lio_tpg_attrib *a = &tpg->tpg_attrib;		   \
1540692e5d73SJames Smart 	unsigned long val;						   \
1541692e5d73SJames Smart 	int ret;							   \
1542692e5d73SJames Smart 									   \
1543692e5d73SJames Smart 	ret = kstrtoul(page, 0, &val);					   \
1544692e5d73SJames Smart 	if (ret < 0) {							   \
1545692e5d73SJames Smart 		pr_err("kstrtoul() failed with ret: %d\n", ret);	   \
1546692e5d73SJames Smart 		return ret;						   \
1547692e5d73SJames Smart 	}								   \
1548692e5d73SJames Smart 									   \
1549692e5d73SJames Smart 	if (val != 0 && val != 1) {					   \
1550692e5d73SJames Smart 		pr_err("Illegal boolean value %lu\n", val);		   \
1551692e5d73SJames Smart 		return -EINVAL;						   \
1552692e5d73SJames Smart 	}								   \
1553692e5d73SJames Smart 									   \
1554692e5d73SJames Smart 	a->name = val;							   \
1555692e5d73SJames Smart 									   \
1556692e5d73SJames Smart 	return count;							   \
1557692e5d73SJames Smart }									   \
1558692e5d73SJames Smart CONFIGFS_ATTR(efct_lio_npiv_tpg_attrib_, name)
1559692e5d73SJames Smart 
1560692e5d73SJames Smart DEF_EFCT_NPIV_TPG_ATTRIB(generate_node_acls);
1561692e5d73SJames Smart DEF_EFCT_NPIV_TPG_ATTRIB(cache_dynamic_acls);
1562692e5d73SJames Smart DEF_EFCT_NPIV_TPG_ATTRIB(demo_mode_write_protect);
1563692e5d73SJames Smart DEF_EFCT_NPIV_TPG_ATTRIB(prod_mode_write_protect);
1564692e5d73SJames Smart DEF_EFCT_NPIV_TPG_ATTRIB(demo_mode_login_only);
1565692e5d73SJames Smart DEF_EFCT_NPIV_TPG_ATTRIB(session_deletion_wait);
1566692e5d73SJames Smart 
1567692e5d73SJames Smart static struct configfs_attribute *efct_lio_npiv_tpg_attrib_attrs[] = {
1568692e5d73SJames Smart 	&efct_lio_npiv_tpg_attrib_attr_generate_node_acls,
1569692e5d73SJames Smart 	&efct_lio_npiv_tpg_attrib_attr_cache_dynamic_acls,
1570692e5d73SJames Smart 	&efct_lio_npiv_tpg_attrib_attr_demo_mode_write_protect,
1571692e5d73SJames Smart 	&efct_lio_npiv_tpg_attrib_attr_prod_mode_write_protect,
1572692e5d73SJames Smart 	&efct_lio_npiv_tpg_attrib_attr_demo_mode_login_only,
1573692e5d73SJames Smart 	&efct_lio_npiv_tpg_attrib_attr_session_deletion_wait,
1574692e5d73SJames Smart 	NULL,
1575692e5d73SJames Smart };
1576692e5d73SJames Smart 
1577692e5d73SJames Smart CONFIGFS_ATTR(efct_lio_tpg_, enable);
1578692e5d73SJames Smart static struct configfs_attribute *efct_lio_tpg_attrs[] = {
1579692e5d73SJames Smart 				&efct_lio_tpg_attr_enable, NULL };
1580692e5d73SJames Smart CONFIGFS_ATTR(efct_lio_npiv_tpg_, enable);
1581692e5d73SJames Smart static struct configfs_attribute *efct_lio_npiv_tpg_attrs[] = {
1582692e5d73SJames Smart 				&efct_lio_npiv_tpg_attr_enable, NULL };
1583692e5d73SJames Smart 
1584692e5d73SJames Smart static const struct target_core_fabric_ops efct_lio_ops = {
1585692e5d73SJames Smart 	.module				= THIS_MODULE,
1586692e5d73SJames Smart 	.fabric_name			= "efct",
1587692e5d73SJames Smart 	.node_acl_size			= sizeof(struct efct_lio_nacl),
1588692e5d73SJames Smart 	.max_data_sg_nents		= 65535,
1589692e5d73SJames Smart 	.tpg_get_wwn			= efct_lio_get_fabric_wwn,
1590692e5d73SJames Smart 	.tpg_get_tag			= efct_lio_get_tag,
1591692e5d73SJames Smart 	.fabric_init_nodeacl		= efct_lio_init_nodeacl,
1592692e5d73SJames Smart 	.tpg_check_demo_mode		= efct_lio_check_demo_mode,
1593692e5d73SJames Smart 	.tpg_check_demo_mode_cache      = efct_lio_check_demo_mode_cache,
1594692e5d73SJames Smart 	.tpg_check_demo_mode_write_protect = efct_lio_check_demo_write_protect,
1595692e5d73SJames Smart 	.tpg_check_prod_mode_write_protect = efct_lio_check_prod_write_protect,
1596692e5d73SJames Smart 	.check_stop_free		= efct_lio_check_stop_free,
1597692e5d73SJames Smart 	.aborted_task			= efct_lio_aborted_task,
1598692e5d73SJames Smart 	.release_cmd			= efct_lio_release_cmd,
1599692e5d73SJames Smart 	.close_session			= efct_lio_close_session,
1600692e5d73SJames Smart 	.write_pending			= efct_lio_write_pending,
1601692e5d73SJames Smart 	.get_cmd_state			= efct_lio_get_cmd_state,
1602692e5d73SJames Smart 	.queue_data_in			= efct_lio_queue_data_in,
1603692e5d73SJames Smart 	.queue_status			= efct_lio_queue_status,
1604692e5d73SJames Smart 	.queue_tm_rsp			= efct_lio_queue_tm_rsp,
1605692e5d73SJames Smart 	.fabric_make_wwn		= efct_lio_make_nport,
1606692e5d73SJames Smart 	.fabric_drop_wwn		= efct_lio_drop_nport,
1607692e5d73SJames Smart 	.fabric_make_tpg		= efct_lio_make_tpg,
1608692e5d73SJames Smart 	.fabric_drop_tpg		= efct_lio_drop_tpg,
1609692e5d73SJames Smart 	.tpg_check_demo_mode_login_only = efct_lio_check_demo_mode_login_only,
1610692e5d73SJames Smart 	.tpg_check_prot_fabric_only	= NULL,
1611692e5d73SJames Smart 	.sess_get_initiator_sid		= NULL,
1612692e5d73SJames Smart 	.tfc_tpg_base_attrs		= efct_lio_tpg_attrs,
1613692e5d73SJames Smart 	.tfc_tpg_attrib_attrs           = efct_lio_tpg_attrib_attrs,
1614692e5d73SJames Smart };
1615692e5d73SJames Smart 
1616692e5d73SJames Smart static const struct target_core_fabric_ops efct_lio_npiv_ops = {
1617692e5d73SJames Smart 	.module				= THIS_MODULE,
1618692e5d73SJames Smart 	.fabric_name			= "efct_npiv",
1619692e5d73SJames Smart 	.node_acl_size			= sizeof(struct efct_lio_nacl),
1620692e5d73SJames Smart 	.max_data_sg_nents		= 65535,
1621692e5d73SJames Smart 	.tpg_get_wwn			= efct_lio_get_npiv_fabric_wwn,
1622692e5d73SJames Smart 	.tpg_get_tag			= efct_lio_get_npiv_tag,
1623692e5d73SJames Smart 	.fabric_init_nodeacl		= efct_lio_init_nodeacl,
1624692e5d73SJames Smart 	.tpg_check_demo_mode		= efct_lio_check_demo_mode,
1625692e5d73SJames Smart 	.tpg_check_demo_mode_cache      = efct_lio_check_demo_mode_cache,
1626692e5d73SJames Smart 	.tpg_check_demo_mode_write_protect =
1627692e5d73SJames Smart 					efct_lio_npiv_check_demo_write_protect,
1628692e5d73SJames Smart 	.tpg_check_prod_mode_write_protect =
1629692e5d73SJames Smart 					efct_lio_npiv_check_prod_write_protect,
1630692e5d73SJames Smart 	.check_stop_free		= efct_lio_check_stop_free,
1631692e5d73SJames Smart 	.aborted_task			= efct_lio_aborted_task,
1632692e5d73SJames Smart 	.release_cmd			= efct_lio_release_cmd,
1633692e5d73SJames Smart 	.close_session			= efct_lio_close_session,
1634692e5d73SJames Smart 	.write_pending			= efct_lio_write_pending,
1635692e5d73SJames Smart 	.get_cmd_state			= efct_lio_get_cmd_state,
1636692e5d73SJames Smart 	.queue_data_in			= efct_lio_queue_data_in,
1637692e5d73SJames Smart 	.queue_status			= efct_lio_queue_status,
1638692e5d73SJames Smart 	.queue_tm_rsp			= efct_lio_queue_tm_rsp,
1639692e5d73SJames Smart 	.fabric_make_wwn		= efct_lio_npiv_make_nport,
1640692e5d73SJames Smart 	.fabric_drop_wwn		= efct_lio_npiv_drop_nport,
1641692e5d73SJames Smart 	.fabric_make_tpg		= efct_lio_npiv_make_tpg,
1642692e5d73SJames Smart 	.fabric_drop_tpg		= efct_lio_npiv_drop_tpg,
1643692e5d73SJames Smart 	.tpg_check_demo_mode_login_only =
1644692e5d73SJames Smart 				efct_lio_npiv_check_demo_mode_login_only,
1645692e5d73SJames Smart 	.tpg_check_prot_fabric_only	= NULL,
1646692e5d73SJames Smart 	.sess_get_initiator_sid		= NULL,
1647692e5d73SJames Smart 	.tfc_tpg_base_attrs		= efct_lio_npiv_tpg_attrs,
1648692e5d73SJames Smart 	.tfc_tpg_attrib_attrs		= efct_lio_npiv_tpg_attrib_attrs,
1649692e5d73SJames Smart };
1650692e5d73SJames Smart 
efct_scsi_tgt_driver_init(void)1651692e5d73SJames Smart int efct_scsi_tgt_driver_init(void)
1652692e5d73SJames Smart {
1653692e5d73SJames Smart 	int rc;
1654692e5d73SJames Smart 
1655692e5d73SJames Smart 	/* Register the top level struct config_item_type with TCM core */
1656692e5d73SJames Smart 	rc = target_register_template(&efct_lio_ops);
1657692e5d73SJames Smart 	if (rc < 0) {
1658692e5d73SJames Smart 		pr_err("target_fabric_configfs_register failed with %d\n", rc);
1659692e5d73SJames Smart 		return rc;
1660692e5d73SJames Smart 	}
1661692e5d73SJames Smart 	rc = target_register_template(&efct_lio_npiv_ops);
1662692e5d73SJames Smart 	if (rc < 0) {
1663692e5d73SJames Smart 		pr_err("target_fabric_configfs_register failed with %d\n", rc);
1664692e5d73SJames Smart 		target_unregister_template(&efct_lio_ops);
1665692e5d73SJames Smart 		return rc;
1666692e5d73SJames Smart 	}
1667692e5d73SJames Smart 	return 0;
1668692e5d73SJames Smart }
1669692e5d73SJames Smart 
efct_scsi_tgt_driver_exit(void)1670692e5d73SJames Smart int efct_scsi_tgt_driver_exit(void)
1671692e5d73SJames Smart {
1672692e5d73SJames Smart 	target_unregister_template(&efct_lio_ops);
1673692e5d73SJames Smart 	target_unregister_template(&efct_lio_npiv_ops);
1674692e5d73SJames Smart 	return 0;
1675692e5d73SJames Smart }
1676