xref: /openbmc/linux/drivers/target/tcm_fc/tfc_sess.c (revision c0e297dc)
1 /*
2  * Copyright (c) 2010 Cisco Systems, Inc.
3  *
4  * This program is free software; you can redistribute it and/or modify it
5  * under the terms and conditions of the GNU General Public License,
6  * version 2, as published by the Free Software Foundation.
7  *
8  * This program is distributed in the hope it will be useful, but WITHOUT
9  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
10  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
11  * more details.
12  *
13  * You should have received a copy of the GNU General Public License along with
14  * this program; if not, write to the Free Software Foundation, Inc.,
15  * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
16  */
17 
18 /* XXX TBD some includes may be extraneous */
19 
20 #include <linux/module.h>
21 #include <linux/moduleparam.h>
22 #include <linux/utsname.h>
23 #include <linux/init.h>
24 #include <linux/slab.h>
25 #include <linux/kthread.h>
26 #include <linux/types.h>
27 #include <linux/string.h>
28 #include <linux/configfs.h>
29 #include <linux/ctype.h>
30 #include <linux/hash.h>
31 #include <linux/rcupdate.h>
32 #include <linux/rculist.h>
33 #include <linux/kref.h>
34 #include <asm/unaligned.h>
35 #include <scsi/libfc.h>
36 
37 #include <target/target_core_base.h>
38 #include <target/target_core_fabric.h>
39 #include <target/configfs_macros.h>
40 
41 #include "tcm_fc.h"
42 
43 static void ft_sess_delete_all(struct ft_tport *);
44 
45 /*
46  * Lookup or allocate target local port.
47  * Caller holds ft_lport_lock.
48  */
49 static struct ft_tport *ft_tport_get(struct fc_lport *lport)
50 {
51 	struct ft_tpg *tpg;
52 	struct ft_tport *tport;
53 	int i;
54 
55 	tport = rcu_dereference_protected(lport->prov[FC_TYPE_FCP],
56 					  lockdep_is_held(&ft_lport_lock));
57 	if (tport && tport->tpg)
58 		return tport;
59 
60 	tpg = ft_lport_find_tpg(lport);
61 	if (!tpg)
62 		return NULL;
63 
64 	if (tport) {
65 		tport->tpg = tpg;
66 		tpg->tport = tport;
67 		return tport;
68 	}
69 
70 	tport = kzalloc(sizeof(*tport), GFP_KERNEL);
71 	if (!tport)
72 		return NULL;
73 
74 	tport->lport = lport;
75 	tport->tpg = tpg;
76 	tpg->tport = tport;
77 	for (i = 0; i < FT_SESS_HASH_SIZE; i++)
78 		INIT_HLIST_HEAD(&tport->hash[i]);
79 
80 	rcu_assign_pointer(lport->prov[FC_TYPE_FCP], tport);
81 	return tport;
82 }
83 
84 /*
85  * Delete a target local port.
86  * Caller holds ft_lport_lock.
87  */
88 static void ft_tport_delete(struct ft_tport *tport)
89 {
90 	struct fc_lport *lport;
91 	struct ft_tpg *tpg;
92 
93 	ft_sess_delete_all(tport);
94 	lport = tport->lport;
95 	BUG_ON(tport != lport->prov[FC_TYPE_FCP]);
96 	RCU_INIT_POINTER(lport->prov[FC_TYPE_FCP], NULL);
97 
98 	tpg = tport->tpg;
99 	if (tpg) {
100 		tpg->tport = NULL;
101 		tport->tpg = NULL;
102 	}
103 	kfree_rcu(tport, rcu);
104 }
105 
106 /*
107  * Add local port.
108  * Called thru fc_lport_iterate().
109  */
110 void ft_lport_add(struct fc_lport *lport, void *arg)
111 {
112 	mutex_lock(&ft_lport_lock);
113 	ft_tport_get(lport);
114 	mutex_unlock(&ft_lport_lock);
115 }
116 
117 /*
118  * Delete local port.
119  * Called thru fc_lport_iterate().
120  */
121 void ft_lport_del(struct fc_lport *lport, void *arg)
122 {
123 	struct ft_tport *tport;
124 
125 	mutex_lock(&ft_lport_lock);
126 	tport = lport->prov[FC_TYPE_FCP];
127 	if (tport)
128 		ft_tport_delete(tport);
129 	mutex_unlock(&ft_lport_lock);
130 }
131 
132 /*
133  * Notification of local port change from libfc.
134  * Create or delete local port and associated tport.
135  */
136 int ft_lport_notify(struct notifier_block *nb, unsigned long event, void *arg)
137 {
138 	struct fc_lport *lport = arg;
139 
140 	switch (event) {
141 	case FC_LPORT_EV_ADD:
142 		ft_lport_add(lport, NULL);
143 		break;
144 	case FC_LPORT_EV_DEL:
145 		ft_lport_del(lport, NULL);
146 		break;
147 	}
148 	return NOTIFY_DONE;
149 }
150 
151 /*
152  * Hash function for FC_IDs.
153  */
154 static u32 ft_sess_hash(u32 port_id)
155 {
156 	return hash_32(port_id, FT_SESS_HASH_BITS);
157 }
158 
159 /*
160  * Find session in local port.
161  * Sessions and hash lists are RCU-protected.
162  * A reference is taken which must be eventually freed.
163  */
164 static struct ft_sess *ft_sess_get(struct fc_lport *lport, u32 port_id)
165 {
166 	struct ft_tport *tport;
167 	struct hlist_head *head;
168 	struct ft_sess *sess;
169 
170 	rcu_read_lock();
171 	tport = rcu_dereference(lport->prov[FC_TYPE_FCP]);
172 	if (!tport)
173 		goto out;
174 
175 	head = &tport->hash[ft_sess_hash(port_id)];
176 	hlist_for_each_entry_rcu(sess, head, hash) {
177 		if (sess->port_id == port_id) {
178 			kref_get(&sess->kref);
179 			rcu_read_unlock();
180 			pr_debug("port_id %x found %p\n", port_id, sess);
181 			return sess;
182 		}
183 	}
184 out:
185 	rcu_read_unlock();
186 	pr_debug("port_id %x not found\n", port_id);
187 	return NULL;
188 }
189 
190 /*
191  * Allocate session and enter it in the hash for the local port.
192  * Caller holds ft_lport_lock.
193  */
194 static struct ft_sess *ft_sess_create(struct ft_tport *tport, u32 port_id,
195 				      struct ft_node_acl *acl)
196 {
197 	struct ft_sess *sess;
198 	struct hlist_head *head;
199 
200 	head = &tport->hash[ft_sess_hash(port_id)];
201 	hlist_for_each_entry_rcu(sess, head, hash)
202 		if (sess->port_id == port_id)
203 			return sess;
204 
205 	sess = kzalloc(sizeof(*sess), GFP_KERNEL);
206 	if (!sess)
207 		return NULL;
208 
209 	sess->se_sess = transport_init_session_tags(TCM_FC_DEFAULT_TAGS,
210 						    sizeof(struct ft_cmd),
211 						    TARGET_PROT_NORMAL);
212 	if (IS_ERR(sess->se_sess)) {
213 		kfree(sess);
214 		return NULL;
215 	}
216 	sess->se_sess->se_node_acl = &acl->se_node_acl;
217 	sess->tport = tport;
218 	sess->port_id = port_id;
219 	kref_init(&sess->kref);	/* ref for table entry */
220 	hlist_add_head_rcu(&sess->hash, head);
221 	tport->sess_count++;
222 
223 	pr_debug("port_id %x sess %p\n", port_id, sess);
224 
225 	transport_register_session(&tport->tpg->se_tpg, &acl->se_node_acl,
226 				   sess->se_sess, sess);
227 	return sess;
228 }
229 
230 /*
231  * Unhash the session.
232  * Caller holds ft_lport_lock.
233  */
234 static void ft_sess_unhash(struct ft_sess *sess)
235 {
236 	struct ft_tport *tport = sess->tport;
237 
238 	hlist_del_rcu(&sess->hash);
239 	BUG_ON(!tport->sess_count);
240 	tport->sess_count--;
241 	sess->port_id = -1;
242 	sess->params = 0;
243 }
244 
245 /*
246  * Delete session from hash.
247  * Caller holds ft_lport_lock.
248  */
249 static struct ft_sess *ft_sess_delete(struct ft_tport *tport, u32 port_id)
250 {
251 	struct hlist_head *head;
252 	struct ft_sess *sess;
253 
254 	head = &tport->hash[ft_sess_hash(port_id)];
255 	hlist_for_each_entry_rcu(sess, head, hash) {
256 		if (sess->port_id == port_id) {
257 			ft_sess_unhash(sess);
258 			return sess;
259 		}
260 	}
261 	return NULL;
262 }
263 
264 /*
265  * Delete all sessions from tport.
266  * Caller holds ft_lport_lock.
267  */
268 static void ft_sess_delete_all(struct ft_tport *tport)
269 {
270 	struct hlist_head *head;
271 	struct ft_sess *sess;
272 
273 	for (head = tport->hash;
274 	     head < &tport->hash[FT_SESS_HASH_SIZE]; head++) {
275 		hlist_for_each_entry_rcu(sess, head, hash) {
276 			ft_sess_unhash(sess);
277 			transport_deregister_session_configfs(sess->se_sess);
278 			ft_sess_put(sess);	/* release from table */
279 		}
280 	}
281 }
282 
283 /*
284  * TCM ops for sessions.
285  */
286 
287 /*
288  * Determine whether session is allowed to be shutdown in the current context.
289  * Returns non-zero if the session should be shutdown.
290  */
291 int ft_sess_shutdown(struct se_session *se_sess)
292 {
293 	struct ft_sess *sess = se_sess->fabric_sess_ptr;
294 
295 	pr_debug("port_id %x\n", sess->port_id);
296 	return 1;
297 }
298 
299 /*
300  * Remove session and send PRLO.
301  * This is called when the ACL is being deleted or queue depth is changing.
302  */
303 void ft_sess_close(struct se_session *se_sess)
304 {
305 	struct ft_sess *sess = se_sess->fabric_sess_ptr;
306 	u32 port_id;
307 
308 	mutex_lock(&ft_lport_lock);
309 	port_id = sess->port_id;
310 	if (port_id == -1) {
311 		mutex_unlock(&ft_lport_lock);
312 		return;
313 	}
314 	pr_debug("port_id %x\n", port_id);
315 	ft_sess_unhash(sess);
316 	mutex_unlock(&ft_lport_lock);
317 	transport_deregister_session_configfs(se_sess);
318 	ft_sess_put(sess);
319 	/* XXX Send LOGO or PRLO */
320 	synchronize_rcu();		/* let transport deregister happen */
321 }
322 
323 u32 ft_sess_get_index(struct se_session *se_sess)
324 {
325 	struct ft_sess *sess = se_sess->fabric_sess_ptr;
326 
327 	return sess->port_id;	/* XXX TBD probably not what is needed */
328 }
329 
330 u32 ft_sess_get_port_name(struct se_session *se_sess,
331 			  unsigned char *buf, u32 len)
332 {
333 	struct ft_sess *sess = se_sess->fabric_sess_ptr;
334 
335 	return ft_format_wwn(buf, len, sess->port_name);
336 }
337 
338 /*
339  * libfc ops involving sessions.
340  */
341 
342 static int ft_prli_locked(struct fc_rport_priv *rdata, u32 spp_len,
343 			  const struct fc_els_spp *rspp, struct fc_els_spp *spp)
344 {
345 	struct ft_tport *tport;
346 	struct ft_sess *sess;
347 	struct ft_node_acl *acl;
348 	u32 fcp_parm;
349 
350 	tport = ft_tport_get(rdata->local_port);
351 	if (!tport)
352 		goto not_target;	/* not a target for this local port */
353 
354 	acl = ft_acl_get(tport->tpg, rdata);
355 	if (!acl)
356 		goto not_target;	/* no target for this remote */
357 
358 	if (!rspp)
359 		goto fill;
360 
361 	if (rspp->spp_flags & (FC_SPP_OPA_VAL | FC_SPP_RPA_VAL))
362 		return FC_SPP_RESP_NO_PA;
363 
364 	/*
365 	 * If both target and initiator bits are off, the SPP is invalid.
366 	 */
367 	fcp_parm = ntohl(rspp->spp_params);
368 	if (!(fcp_parm & (FCP_SPPF_INIT_FCN | FCP_SPPF_TARG_FCN)))
369 		return FC_SPP_RESP_INVL;
370 
371 	/*
372 	 * Create session (image pair) only if requested by
373 	 * EST_IMG_PAIR flag and if the requestor is an initiator.
374 	 */
375 	if (rspp->spp_flags & FC_SPP_EST_IMG_PAIR) {
376 		spp->spp_flags |= FC_SPP_EST_IMG_PAIR;
377 		if (!(fcp_parm & FCP_SPPF_INIT_FCN))
378 			return FC_SPP_RESP_CONF;
379 		sess = ft_sess_create(tport, rdata->ids.port_id, acl);
380 		if (!sess)
381 			return FC_SPP_RESP_RES;
382 		if (!sess->params)
383 			rdata->prli_count++;
384 		sess->params = fcp_parm;
385 		sess->port_name = rdata->ids.port_name;
386 		sess->max_frame = rdata->maxframe_size;
387 
388 		/* XXX TBD - clearing actions.  unit attn, see 4.10 */
389 	}
390 
391 	/*
392 	 * OR in our service parameters with other provider (initiator), if any.
393 	 */
394 fill:
395 	fcp_parm = ntohl(spp->spp_params);
396 	fcp_parm &= ~FCP_SPPF_RETRY;
397 	spp->spp_params = htonl(fcp_parm | FCP_SPPF_TARG_FCN);
398 	return FC_SPP_RESP_ACK;
399 
400 not_target:
401 	fcp_parm = ntohl(spp->spp_params);
402 	fcp_parm &= ~FCP_SPPF_TARG_FCN;
403 	spp->spp_params = htonl(fcp_parm);
404 	return 0;
405 }
406 
407 /**
408  * tcm_fcp_prli() - Handle incoming or outgoing PRLI for the FCP target
409  * @rdata: remote port private
410  * @spp_len: service parameter page length
411  * @rspp: received service parameter page (NULL for outgoing PRLI)
412  * @spp: response service parameter page
413  *
414  * Returns spp response code.
415  */
416 static int ft_prli(struct fc_rport_priv *rdata, u32 spp_len,
417 		   const struct fc_els_spp *rspp, struct fc_els_spp *spp)
418 {
419 	int ret;
420 
421 	mutex_lock(&ft_lport_lock);
422 	ret = ft_prli_locked(rdata, spp_len, rspp, spp);
423 	mutex_unlock(&ft_lport_lock);
424 	pr_debug("port_id %x flags %x ret %x\n",
425 	       rdata->ids.port_id, rspp ? rspp->spp_flags : 0, ret);
426 	return ret;
427 }
428 
429 static void ft_sess_free(struct kref *kref)
430 {
431 	struct ft_sess *sess = container_of(kref, struct ft_sess, kref);
432 
433 	transport_deregister_session(sess->se_sess);
434 	kfree_rcu(sess, rcu);
435 }
436 
437 void ft_sess_put(struct ft_sess *sess)
438 {
439 	int sess_held = atomic_read(&sess->kref.refcount);
440 
441 	BUG_ON(!sess_held);
442 	kref_put(&sess->kref, ft_sess_free);
443 }
444 
445 static void ft_prlo(struct fc_rport_priv *rdata)
446 {
447 	struct ft_sess *sess;
448 	struct ft_tport *tport;
449 
450 	mutex_lock(&ft_lport_lock);
451 	tport = rcu_dereference_protected(rdata->local_port->prov[FC_TYPE_FCP],
452 					  lockdep_is_held(&ft_lport_lock));
453 
454 	if (!tport) {
455 		mutex_unlock(&ft_lport_lock);
456 		return;
457 	}
458 	sess = ft_sess_delete(tport, rdata->ids.port_id);
459 	if (!sess) {
460 		mutex_unlock(&ft_lport_lock);
461 		return;
462 	}
463 	mutex_unlock(&ft_lport_lock);
464 	transport_deregister_session_configfs(sess->se_sess);
465 	ft_sess_put(sess);		/* release from table */
466 	rdata->prli_count--;
467 	/* XXX TBD - clearing actions.  unit attn, see 4.10 */
468 }
469 
470 /*
471  * Handle incoming FCP request.
472  * Caller has verified that the frame is type FCP.
473  */
474 static void ft_recv(struct fc_lport *lport, struct fc_frame *fp)
475 {
476 	struct ft_sess *sess;
477 	u32 sid = fc_frame_sid(fp);
478 
479 	pr_debug("sid %x\n", sid);
480 
481 	sess = ft_sess_get(lport, sid);
482 	if (!sess) {
483 		pr_debug("sid %x sess lookup failed\n", sid);
484 		/* TBD XXX - if FCP_CMND, send PRLO */
485 		fc_frame_free(fp);
486 		return;
487 	}
488 	ft_recv_req(sess, fp);	/* must do ft_sess_put() */
489 }
490 
491 /*
492  * Provider ops for libfc.
493  */
494 struct fc4_prov ft_prov = {
495 	.prli = ft_prli,
496 	.prlo = ft_prlo,
497 	.recv = ft_recv,
498 	.module = THIS_MODULE,
499 };
500