tfc_sess.c 11 KB

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