0001
0002
0003
0004
0005
0006
0007
0008 #include <linux/module.h>
0009 #include <linux/moduleparam.h>
0010 #include <linux/utsname.h>
0011 #include <linux/init.h>
0012 #include <linux/slab.h>
0013 #include <linux/kthread.h>
0014 #include <linux/types.h>
0015 #include <linux/string.h>
0016 #include <linux/configfs.h>
0017 #include <linux/ctype.h>
0018 #include <linux/hash.h>
0019 #include <linux/rcupdate.h>
0020 #include <linux/rculist.h>
0021 #include <linux/kref.h>
0022 #include <asm/unaligned.h>
0023 #include <scsi/libfc.h>
0024
0025 #include <target/target_core_base.h>
0026 #include <target/target_core_fabric.h>
0027
0028 #include "tcm_fc.h"
0029
0030 #define TFC_SESS_DBG(lport, fmt, args...) \
0031 pr_debug("host%u: rport %6.6x: " fmt, \
0032 (lport)->host->host_no, \
0033 (lport)->port_id, ##args )
0034
0035 static void ft_sess_delete_all(struct ft_tport *);
0036
0037
0038
0039
0040
0041 static struct ft_tport *ft_tport_get(struct fc_lport *lport)
0042 {
0043 struct ft_tpg *tpg;
0044 struct ft_tport *tport;
0045 int i;
0046
0047 tport = rcu_dereference_protected(lport->prov[FC_TYPE_FCP],
0048 lockdep_is_held(&ft_lport_lock));
0049 if (tport && tport->tpg)
0050 return tport;
0051
0052 tpg = ft_lport_find_tpg(lport);
0053 if (!tpg)
0054 return NULL;
0055
0056 if (tport) {
0057 tport->tpg = tpg;
0058 tpg->tport = tport;
0059 return tport;
0060 }
0061
0062 tport = kzalloc(sizeof(*tport), GFP_KERNEL);
0063 if (!tport)
0064 return NULL;
0065
0066 tport->lport = lport;
0067 tport->tpg = tpg;
0068 tpg->tport = tport;
0069 for (i = 0; i < FT_SESS_HASH_SIZE; i++)
0070 INIT_HLIST_HEAD(&tport->hash[i]);
0071
0072 rcu_assign_pointer(lport->prov[FC_TYPE_FCP], tport);
0073 return tport;
0074 }
0075
0076
0077
0078
0079
0080 static void ft_tport_delete(struct ft_tport *tport)
0081 {
0082 struct fc_lport *lport;
0083 struct ft_tpg *tpg;
0084
0085 ft_sess_delete_all(tport);
0086 lport = tport->lport;
0087 lport->service_params &= ~FCP_SPPF_TARG_FCN;
0088 BUG_ON(tport != lport->prov[FC_TYPE_FCP]);
0089 RCU_INIT_POINTER(lport->prov[FC_TYPE_FCP], NULL);
0090
0091 tpg = tport->tpg;
0092 if (tpg) {
0093 tpg->tport = NULL;
0094 tport->tpg = NULL;
0095 }
0096 kfree_rcu(tport, rcu);
0097 }
0098
0099
0100
0101
0102
0103 void ft_lport_add(struct fc_lport *lport, void *arg)
0104 {
0105 mutex_lock(&ft_lport_lock);
0106 ft_tport_get(lport);
0107 lport->service_params |= FCP_SPPF_TARG_FCN;
0108 mutex_unlock(&ft_lport_lock);
0109 }
0110
0111
0112
0113
0114
0115 void ft_lport_del(struct fc_lport *lport, void *arg)
0116 {
0117 struct ft_tport *tport;
0118
0119 mutex_lock(&ft_lport_lock);
0120 tport = lport->prov[FC_TYPE_FCP];
0121 if (tport)
0122 ft_tport_delete(tport);
0123 mutex_unlock(&ft_lport_lock);
0124 }
0125
0126
0127
0128
0129
0130 int ft_lport_notify(struct notifier_block *nb, unsigned long event, void *arg)
0131 {
0132 struct fc_lport *lport = arg;
0133
0134 switch (event) {
0135 case FC_LPORT_EV_ADD:
0136 ft_lport_add(lport, NULL);
0137 break;
0138 case FC_LPORT_EV_DEL:
0139 ft_lport_del(lport, NULL);
0140 break;
0141 }
0142 return NOTIFY_DONE;
0143 }
0144
0145
0146
0147
0148 static u32 ft_sess_hash(u32 port_id)
0149 {
0150 return hash_32(port_id, FT_SESS_HASH_BITS);
0151 }
0152
0153
0154
0155
0156
0157
0158 static struct ft_sess *ft_sess_get(struct fc_lport *lport, u32 port_id)
0159 {
0160 struct ft_tport *tport;
0161 struct hlist_head *head;
0162 struct ft_sess *sess;
0163 char *reason = "no session created";
0164
0165 rcu_read_lock();
0166 tport = rcu_dereference(lport->prov[FC_TYPE_FCP]);
0167 if (!tport) {
0168 reason = "not an FCP port";
0169 goto out;
0170 }
0171
0172 head = &tport->hash[ft_sess_hash(port_id)];
0173 hlist_for_each_entry_rcu(sess, head, hash) {
0174 if (sess->port_id == port_id) {
0175 kref_get(&sess->kref);
0176 rcu_read_unlock();
0177 TFC_SESS_DBG(lport, "port_id %x found %p\n",
0178 port_id, sess);
0179 return sess;
0180 }
0181 }
0182 out:
0183 rcu_read_unlock();
0184 TFC_SESS_DBG(lport, "port_id %x not found, %s\n",
0185 port_id, reason);
0186 return NULL;
0187 }
0188
0189 static int ft_sess_alloc_cb(struct se_portal_group *se_tpg,
0190 struct se_session *se_sess, void *p)
0191 {
0192 struct ft_sess *sess = p;
0193 struct ft_tport *tport = sess->tport;
0194 struct hlist_head *head = &tport->hash[ft_sess_hash(sess->port_id)];
0195
0196 TFC_SESS_DBG(tport->lport, "port_id %x sess %p\n", sess->port_id, sess);
0197 hlist_add_head_rcu(&sess->hash, head);
0198 tport->sess_count++;
0199
0200 return 0;
0201 }
0202
0203
0204
0205
0206
0207 static struct ft_sess *ft_sess_create(struct ft_tport *tport, u32 port_id,
0208 struct fc_rport_priv *rdata)
0209 {
0210 struct se_portal_group *se_tpg = &tport->tpg->se_tpg;
0211 struct ft_sess *sess;
0212 struct hlist_head *head;
0213 unsigned char initiatorname[TRANSPORT_IQN_LEN];
0214
0215 ft_format_wwn(&initiatorname[0], TRANSPORT_IQN_LEN, rdata->ids.port_name);
0216
0217 head = &tport->hash[ft_sess_hash(port_id)];
0218 hlist_for_each_entry_rcu(sess, head, hash)
0219 if (sess->port_id == port_id)
0220 return sess;
0221
0222 sess = kzalloc(sizeof(*sess), GFP_KERNEL);
0223 if (!sess)
0224 return ERR_PTR(-ENOMEM);
0225
0226 kref_init(&sess->kref);
0227 sess->tport = tport;
0228 sess->port_id = port_id;
0229
0230 sess->se_sess = target_setup_session(se_tpg, TCM_FC_DEFAULT_TAGS,
0231 sizeof(struct ft_cmd),
0232 TARGET_PROT_NORMAL, &initiatorname[0],
0233 sess, ft_sess_alloc_cb);
0234 if (IS_ERR(sess->se_sess)) {
0235 int rc = PTR_ERR(sess->se_sess);
0236 kfree(sess);
0237 sess = ERR_PTR(rc);
0238 }
0239 return sess;
0240 }
0241
0242
0243
0244
0245
0246 static void ft_sess_unhash(struct ft_sess *sess)
0247 {
0248 struct ft_tport *tport = sess->tport;
0249
0250 hlist_del_rcu(&sess->hash);
0251 BUG_ON(!tport->sess_count);
0252 tport->sess_count--;
0253 sess->port_id = -1;
0254 sess->params = 0;
0255 }
0256
0257
0258
0259
0260
0261 static struct ft_sess *ft_sess_delete(struct ft_tport *tport, u32 port_id)
0262 {
0263 struct hlist_head *head;
0264 struct ft_sess *sess;
0265
0266 head = &tport->hash[ft_sess_hash(port_id)];
0267 hlist_for_each_entry_rcu(sess, head, hash) {
0268 if (sess->port_id == port_id) {
0269 ft_sess_unhash(sess);
0270 return sess;
0271 }
0272 }
0273 return NULL;
0274 }
0275
0276 static void ft_close_sess(struct ft_sess *sess)
0277 {
0278 target_stop_session(sess->se_sess);
0279 target_wait_for_sess_cmds(sess->se_sess);
0280 ft_sess_put(sess);
0281 }
0282
0283
0284
0285
0286
0287 static void ft_sess_delete_all(struct ft_tport *tport)
0288 {
0289 struct hlist_head *head;
0290 struct ft_sess *sess;
0291
0292 for (head = tport->hash;
0293 head < &tport->hash[FT_SESS_HASH_SIZE]; head++) {
0294 hlist_for_each_entry_rcu(sess, head, hash) {
0295 ft_sess_unhash(sess);
0296 ft_close_sess(sess);
0297 }
0298 }
0299 }
0300
0301
0302
0303
0304
0305
0306
0307
0308
0309 void ft_sess_close(struct se_session *se_sess)
0310 {
0311 struct ft_sess *sess = se_sess->fabric_sess_ptr;
0312 u32 port_id;
0313
0314 mutex_lock(&ft_lport_lock);
0315 port_id = sess->port_id;
0316 if (port_id == -1) {
0317 mutex_unlock(&ft_lport_lock);
0318 return;
0319 }
0320 TFC_SESS_DBG(sess->tport->lport, "port_id %x close session\n", port_id);
0321 ft_sess_unhash(sess);
0322 mutex_unlock(&ft_lport_lock);
0323 ft_close_sess(sess);
0324
0325 synchronize_rcu();
0326 }
0327
0328 u32 ft_sess_get_index(struct se_session *se_sess)
0329 {
0330 struct ft_sess *sess = se_sess->fabric_sess_ptr;
0331
0332 return sess->port_id;
0333 }
0334
0335 u32 ft_sess_get_port_name(struct se_session *se_sess,
0336 unsigned char *buf, u32 len)
0337 {
0338 struct ft_sess *sess = se_sess->fabric_sess_ptr;
0339
0340 return ft_format_wwn(buf, len, sess->port_name);
0341 }
0342
0343
0344
0345
0346
0347 static int ft_prli_locked(struct fc_rport_priv *rdata, u32 spp_len,
0348 const struct fc_els_spp *rspp, struct fc_els_spp *spp)
0349 {
0350 struct ft_tport *tport;
0351 struct ft_sess *sess;
0352 u32 fcp_parm;
0353
0354 tport = ft_tport_get(rdata->local_port);
0355 if (!tport)
0356 goto not_target;
0357
0358 if (!rspp)
0359 goto fill;
0360
0361 if (rspp->spp_flags & (FC_SPP_OPA_VAL | FC_SPP_RPA_VAL))
0362 return FC_SPP_RESP_NO_PA;
0363
0364
0365
0366
0367 fcp_parm = ntohl(rspp->spp_params);
0368 if (!(fcp_parm & (FCP_SPPF_INIT_FCN | FCP_SPPF_TARG_FCN)))
0369 return FC_SPP_RESP_INVL;
0370
0371
0372
0373
0374
0375 if (rspp->spp_flags & FC_SPP_EST_IMG_PAIR) {
0376 spp->spp_flags |= FC_SPP_EST_IMG_PAIR;
0377 if (!(fcp_parm & FCP_SPPF_INIT_FCN))
0378 return FC_SPP_RESP_CONF;
0379 sess = ft_sess_create(tport, rdata->ids.port_id, rdata);
0380 if (IS_ERR(sess)) {
0381 if (PTR_ERR(sess) == -EACCES) {
0382 spp->spp_flags &= ~FC_SPP_EST_IMG_PAIR;
0383 return FC_SPP_RESP_CONF;
0384 } else
0385 return FC_SPP_RESP_RES;
0386 }
0387 if (!sess->params)
0388 rdata->prli_count++;
0389 sess->params = fcp_parm;
0390 sess->port_name = rdata->ids.port_name;
0391 sess->max_frame = rdata->maxframe_size;
0392
0393
0394 }
0395
0396
0397
0398
0399 fill:
0400 fcp_parm = ntohl(spp->spp_params);
0401 fcp_parm &= ~FCP_SPPF_RETRY;
0402 spp->spp_params = htonl(fcp_parm | FCP_SPPF_TARG_FCN);
0403 return FC_SPP_RESP_ACK;
0404
0405 not_target:
0406 fcp_parm = ntohl(spp->spp_params);
0407 fcp_parm &= ~FCP_SPPF_TARG_FCN;
0408 spp->spp_params = htonl(fcp_parm);
0409 return 0;
0410 }
0411
0412
0413
0414
0415
0416
0417
0418
0419
0420
0421 static int ft_prli(struct fc_rport_priv *rdata, u32 spp_len,
0422 const struct fc_els_spp *rspp, struct fc_els_spp *spp)
0423 {
0424 int ret;
0425
0426 mutex_lock(&ft_lport_lock);
0427 ret = ft_prli_locked(rdata, spp_len, rspp, spp);
0428 mutex_unlock(&ft_lport_lock);
0429 TFC_SESS_DBG(rdata->local_port, "port_id %x flags %x ret %x\n",
0430 rdata->ids.port_id, rspp ? rspp->spp_flags : 0, ret);
0431 return ret;
0432 }
0433
0434 static void ft_sess_free(struct kref *kref)
0435 {
0436 struct ft_sess *sess = container_of(kref, struct ft_sess, kref);
0437
0438 target_remove_session(sess->se_sess);
0439 kfree_rcu(sess, rcu);
0440 }
0441
0442 void ft_sess_put(struct ft_sess *sess)
0443 {
0444 int sess_held = kref_read(&sess->kref);
0445
0446 BUG_ON(!sess_held);
0447 kref_put(&sess->kref, ft_sess_free);
0448 }
0449
0450 static void ft_prlo(struct fc_rport_priv *rdata)
0451 {
0452 struct ft_sess *sess;
0453 struct ft_tport *tport;
0454
0455 mutex_lock(&ft_lport_lock);
0456 tport = rcu_dereference_protected(rdata->local_port->prov[FC_TYPE_FCP],
0457 lockdep_is_held(&ft_lport_lock));
0458
0459 if (!tport) {
0460 mutex_unlock(&ft_lport_lock);
0461 return;
0462 }
0463 sess = ft_sess_delete(tport, rdata->ids.port_id);
0464 if (!sess) {
0465 mutex_unlock(&ft_lport_lock);
0466 return;
0467 }
0468 mutex_unlock(&ft_lport_lock);
0469 ft_close_sess(sess);
0470 rdata->prli_count--;
0471
0472 }
0473
0474
0475
0476
0477
0478 static void ft_recv(struct fc_lport *lport, struct fc_frame *fp)
0479 {
0480 struct ft_sess *sess;
0481 u32 sid = fc_frame_sid(fp);
0482
0483 TFC_SESS_DBG(lport, "recv sid %x\n", sid);
0484
0485 sess = ft_sess_get(lport, sid);
0486 if (!sess) {
0487 TFC_SESS_DBG(lport, "sid %x sess lookup failed\n", sid);
0488
0489 fc_frame_free(fp);
0490 return;
0491 }
0492 ft_recv_req(sess, fp);
0493 }
0494
0495
0496
0497
0498 struct fc4_prov ft_prov = {
0499 .prli = ft_prli,
0500 .prlo = ft_prlo,
0501 .recv = ft_recv,
0502 .module = THIS_MODULE,
0503 };