Linux Kernel  3.7.1
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
tfc_sess.c
Go to the documentation of this file.
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/scsi.h>
36 #include <scsi/scsi_host.h>
37 #include <scsi/scsi_device.h>
38 #include <scsi/scsi_cmnd.h>
39 #include <scsi/libfc.h>
40 
44 #include <target/configfs_macros.h>
45 
46 #include "tcm_fc.h"
47 
48 static void ft_sess_delete_all(struct ft_tport *);
49 
50 /*
51  * Lookup or allocate target local port.
52  * Caller holds ft_lport_lock.
53  */
54 static struct ft_tport *ft_tport_create(struct fc_lport *lport)
55 {
56  struct ft_tpg *tpg;
57  struct ft_tport *tport;
58  int i;
59 
61  lockdep_is_held(&ft_lport_lock));
62  if (tport && tport->tpg)
63  return tport;
64 
65  tpg = ft_lport_find_tpg(lport);
66  if (!tpg)
67  return NULL;
68 
69  if (tport) {
70  tport->tpg = tpg;
71  return tport;
72  }
73 
74  tport = kzalloc(sizeof(*tport), GFP_KERNEL);
75  if (!tport)
76  return NULL;
77 
78  tport->lport = lport;
79  tport->tpg = tpg;
80  tpg->tport = tport;
81  for (i = 0; i < FT_SESS_HASH_SIZE; i++)
82  INIT_HLIST_HEAD(&tport->hash[i]);
83 
84  rcu_assign_pointer(lport->prov[FC_TYPE_FCP], tport);
85  return tport;
86 }
87 
88 /*
89  * Delete a target local port.
90  * Caller holds ft_lport_lock.
91  */
92 static void ft_tport_delete(struct ft_tport *tport)
93 {
94  struct fc_lport *lport;
95  struct ft_tpg *tpg;
96 
97  ft_sess_delete_all(tport);
98  lport = tport->lport;
99  BUG_ON(tport != lport->prov[FC_TYPE_FCP]);
101 
102  tpg = tport->tpg;
103  if (tpg) {
104  tpg->tport = NULL;
105  tport->tpg = NULL;
106  }
107  kfree_rcu(tport, rcu);
108 }
109 
110 /*
111  * Add local port.
112  * Called thru fc_lport_iterate().
113  */
114 void ft_lport_add(struct fc_lport *lport, void *arg)
115 {
117  ft_tport_create(lport);
119 }
120 
121 /*
122  * Delete local port.
123  * Called thru fc_lport_iterate().
124  */
125 void ft_lport_del(struct fc_lport *lport, void *arg)
126 {
127  struct ft_tport *tport;
128 
130  tport = lport->prov[FC_TYPE_FCP];
131  if (tport)
132  ft_tport_delete(tport);
134 }
135 
136 /*
137  * Notification of local port change from libfc.
138  * Create or delete local port and associated tport.
139  */
140 int ft_lport_notify(struct notifier_block *nb, unsigned long event, void *arg)
141 {
142  struct fc_lport *lport = arg;
143 
144  switch (event) {
145  case FC_LPORT_EV_ADD:
146  ft_lport_add(lport, NULL);
147  break;
148  case FC_LPORT_EV_DEL:
149  ft_lport_del(lport, NULL);
150  break;
151  }
152  return NOTIFY_DONE;
153 }
154 
155 /*
156  * Hash function for FC_IDs.
157  */
158 static u32 ft_sess_hash(u32 port_id)
159 {
160  return hash_32(port_id, FT_SESS_HASH_BITS);
161 }
162 
163 /*
164  * Find session in local port.
165  * Sessions and hash lists are RCU-protected.
166  * A reference is taken which must be eventually freed.
167  */
168 static struct ft_sess *ft_sess_get(struct fc_lport *lport, u32 port_id)
169 {
170  struct ft_tport *tport;
171  struct hlist_head *head;
172  struct hlist_node *pos;
173  struct ft_sess *sess;
174 
175  rcu_read_lock();
176  tport = rcu_dereference(lport->prov[FC_TYPE_FCP]);
177  if (!tport)
178  goto out;
179 
180  head = &tport->hash[ft_sess_hash(port_id)];
181  hlist_for_each_entry_rcu(sess, pos, head, hash) {
182  if (sess->port_id == port_id) {
183  kref_get(&sess->kref);
184  rcu_read_unlock();
185  pr_debug("port_id %x found %p\n", port_id, sess);
186  return sess;
187  }
188  }
189 out:
190  rcu_read_unlock();
191  pr_debug("port_id %x not found\n", port_id);
192  return NULL;
193 }
194 
195 /*
196  * Allocate session and enter it in the hash for the local port.
197  * Caller holds ft_lport_lock.
198  */
199 static struct ft_sess *ft_sess_create(struct ft_tport *tport, u32 port_id,
200  struct ft_node_acl *acl)
201 {
202  struct ft_sess *sess;
203  struct hlist_head *head;
204  struct hlist_node *pos;
205 
206  head = &tport->hash[ft_sess_hash(port_id)];
207  hlist_for_each_entry_rcu(sess, pos, head, hash)
208  if (sess->port_id == port_id)
209  return sess;
210 
211  sess = kzalloc(sizeof(*sess), GFP_KERNEL);
212  if (!sess)
213  return NULL;
214 
215  sess->se_sess = transport_init_session();
216  if (IS_ERR(sess->se_sess)) {
217  kfree(sess);
218  return NULL;
219  }
220  sess->se_sess->se_node_acl = &acl->se_node_acl;
221  sess->tport = tport;
222  sess->port_id = port_id;
223  kref_init(&sess->kref); /* ref for table entry */
224  hlist_add_head_rcu(&sess->hash, head);
225  tport->sess_count++;
226 
227  pr_debug("port_id %x sess %p\n", port_id, sess);
228 
229  transport_register_session(&tport->tpg->se_tpg, &acl->se_node_acl,
230  sess->se_sess, sess);
231  return sess;
232 }
233 
234 /*
235  * Unhash the session.
236  * Caller holds ft_lport_lock.
237  */
238 static void ft_sess_unhash(struct ft_sess *sess)
239 {
240  struct ft_tport *tport = sess->tport;
241 
242  hlist_del_rcu(&sess->hash);
243  BUG_ON(!tport->sess_count);
244  tport->sess_count--;
245  sess->port_id = -1;
246  sess->params = 0;
247 }
248 
249 /*
250  * Delete session from hash.
251  * Caller holds ft_lport_lock.
252  */
253 static struct ft_sess *ft_sess_delete(struct ft_tport *tport, u32 port_id)
254 {
255  struct hlist_head *head;
256  struct hlist_node *pos;
257  struct ft_sess *sess;
258 
259  head = &tport->hash[ft_sess_hash(port_id)];
260  hlist_for_each_entry_rcu(sess, pos, head, hash) {
261  if (sess->port_id == port_id) {
262  ft_sess_unhash(sess);
263  return sess;
264  }
265  }
266  return NULL;
267 }
268 
269 /*
270  * Delete all sessions from tport.
271  * Caller holds ft_lport_lock.
272  */
273 static void ft_sess_delete_all(struct ft_tport *tport)
274 {
275  struct hlist_head *head;
276  struct hlist_node *pos;
277  struct ft_sess *sess;
278 
279  for (head = tport->hash;
280  head < &tport->hash[FT_SESS_HASH_SIZE]; head++) {
281  hlist_for_each_entry_rcu(sess, pos, head, hash) {
282  ft_sess_unhash(sess);
284  ft_sess_put(sess); /* release from table */
285  }
286  }
287 }
288 
289 /*
290  * TCM ops for sessions.
291  */
292 
293 /*
294  * Determine whether session is allowed to be shutdown in the current context.
295  * Returns non-zero if the session should be shutdown.
296  */
298 {
299  struct ft_sess *sess = se_sess->fabric_sess_ptr;
300 
301  pr_debug("port_id %x\n", sess->port_id);
302  return 1;
303 }
304 
305 /*
306  * Remove session and send PRLO.
307  * This is called when the ACL is being deleted or queue depth is changing.
308  */
310 {
311  struct ft_sess *sess = se_sess->fabric_sess_ptr;
312  u32 port_id;
313 
315  port_id = sess->port_id;
316  if (port_id == -1) {
318  return;
319  }
320  pr_debug("port_id %x\n", port_id);
321  ft_sess_unhash(sess);
324  ft_sess_put(sess);
325  /* XXX Send LOGO or PRLO */
326  synchronize_rcu(); /* let transport deregister happen */
327 }
328 
330 {
331  struct ft_sess *sess = se_sess->fabric_sess_ptr;
332 
333  return sess->port_id; /* XXX TBD probably not what is needed */
334 }
335 
337  unsigned char *buf, u32 len)
338 {
339  struct ft_sess *sess = se_sess->fabric_sess_ptr;
340 
341  return ft_format_wwn(buf, len, sess->port_name);
342 }
343 
344 /*
345  * libfc ops involving sessions.
346  */
347 
348 static int ft_prli_locked(struct fc_rport_priv *rdata, u32 spp_len,
349  const struct fc_els_spp *rspp, struct fc_els_spp *spp)
350 {
351  struct ft_tport *tport;
352  struct ft_sess *sess;
353  struct ft_node_acl *acl;
354  u32 fcp_parm;
355 
356  tport = ft_tport_create(rdata->local_port);
357  if (!tport)
358  return 0; /* not a target for this local port */
359 
360  acl = ft_acl_get(tport->tpg, rdata);
361  if (!acl)
362  return 0;
363 
364  if (!rspp)
365  goto fill;
366 
367  if (rspp->spp_flags & (FC_SPP_OPA_VAL | FC_SPP_RPA_VAL))
368  return FC_SPP_RESP_NO_PA;
369 
370  /*
371  * If both target and initiator bits are off, the SPP is invalid.
372  */
373  fcp_parm = ntohl(rspp->spp_params);
374  if (!(fcp_parm & (FCP_SPPF_INIT_FCN | FCP_SPPF_TARG_FCN)))
375  return FC_SPP_RESP_INVL;
376 
377  /*
378  * Create session (image pair) only if requested by
379  * EST_IMG_PAIR flag and if the requestor is an initiator.
380  */
381  if (rspp->spp_flags & FC_SPP_EST_IMG_PAIR) {
383  if (!(fcp_parm & FCP_SPPF_INIT_FCN))
384  return FC_SPP_RESP_CONF;
385  sess = ft_sess_create(tport, rdata->ids.port_id, acl);
386  if (!sess)
387  return FC_SPP_RESP_RES;
388  if (!sess->params)
389  rdata->prli_count++;
390  sess->params = fcp_parm;
391  sess->port_name = rdata->ids.port_name;
392  sess->max_frame = rdata->maxframe_size;
393 
394  /* XXX TBD - clearing actions. unit attn, see 4.10 */
395  }
396 
397  /*
398  * OR in our service parameters with other provider (initiator), if any.
399  * TBD XXX - indicate RETRY capability?
400  */
401 fill:
402  fcp_parm = ntohl(spp->spp_params);
403  spp->spp_params = htonl(fcp_parm | FCP_SPPF_TARG_FCN);
404  return FC_SPP_RESP_ACK;
405 }
406 
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_rcu_free(struct rcu_head *rcu)
430 {
431  struct ft_sess *sess = container_of(rcu, struct ft_sess, rcu);
432 
434  kfree(sess);
435 }
436 
437 static void ft_sess_free(struct kref *kref)
438 {
439  struct ft_sess *sess = container_of(kref, struct ft_sess, kref);
440 
441  call_rcu(&sess->rcu, ft_sess_rcu_free);
442 }
443 
444 void ft_sess_put(struct ft_sess *sess)
445 {
446  int sess_held = atomic_read(&sess->kref.refcount);
447 
448  BUG_ON(!sess_held);
449  kref_put(&sess->kref, ft_sess_free);
450 }
451 
452 static void ft_prlo(struct fc_rport_priv *rdata)
453 {
454  struct ft_sess *sess;
455  struct ft_tport *tport;
456 
457  mutex_lock(&ft_lport_lock);
458  tport = rcu_dereference_protected(rdata->local_port->prov[FC_TYPE_FCP],
459  lockdep_is_held(&ft_lport_lock));
460 
461  if (!tport) {
462  mutex_unlock(&ft_lport_lock);
463  return;
464  }
465  sess = ft_sess_delete(tport, rdata->ids.port_id);
466  if (!sess) {
467  mutex_unlock(&ft_lport_lock);
468  return;
469  }
470  mutex_unlock(&ft_lport_lock);
472  ft_sess_put(sess); /* release from table */
473  rdata->prli_count--;
474  /* XXX TBD - clearing actions. unit attn, see 4.10 */
475 }
476 
477 /*
478  * Handle incoming FCP request.
479  * Caller has verified that the frame is type FCP.
480  */
481 static void ft_recv(struct fc_lport *lport, struct fc_frame *fp)
482 {
483  struct ft_sess *sess;
484  u32 sid = fc_frame_sid(fp);
485 
486  pr_debug("sid %x\n", sid);
487 
488  sess = ft_sess_get(lport, sid);
489  if (!sess) {
490  pr_debug("sid %x sess lookup failed\n", sid);
491  /* TBD XXX - if FCP_CMND, send PRLO */
492  fc_frame_free(fp);
493  return;
494  }
495  ft_recv_req(sess, fp); /* must do ft_sess_put() */
496 }
497 
498 /*
499  * Provider ops for libfc.
500  */
501 struct fc4_prov ft_prov = {
502  .prli = ft_prli,
503  .prlo = ft_prlo,
504  .recv = ft_recv,
505  .module = THIS_MODULE,
506 };