xref: /spdk/lib/nvmf/fc_ls.c (revision c6c1234de9e0015e670dd0b51bf6ce39ee0e07bd)
1 /*   SPDX-License-Identifier: BSD-3-Clause
2  *   Copyright (C) 2020 Intel Corporation.
3  *   Copyright (c) 2018-2019 Broadcom.  All Rights Reserved.
4  *   The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries.
5  *   Copyright (c) 2023 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
6  */
7 
8 #include "spdk/env.h"
9 #include "spdk/assert.h"
10 #include "spdk/nvmf.h"
11 #include "spdk/nvmf_spec.h"
12 #include "spdk/string.h"
13 #include "spdk/trace.h"
14 #include "spdk/util.h"
15 #include "spdk/endian.h"
16 #include "spdk/log.h"
17 #include "nvmf_internal.h"
18 #include "transport.h"
19 #include "spdk/nvmf_transport.h"
20 
21 #include "nvmf_fc.h"
22 #include "fc_lld.h"
23 
24 /* set to 1 to send ls disconnect in response to ls disconnect from host (per standard) */
25 #define NVMF_FC_LS_SEND_LS_DISCONNECT 0
26 
27 /* Validation Error indexes into the string table below */
28 enum {
29 	VERR_NO_ERROR = 0,
30 	VERR_CR_ASSOC_LEN = 1,
31 	VERR_CR_ASSOC_RQST_LEN = 2,
32 	VERR_CR_ASSOC_CMD = 3,
33 	VERR_CR_ASSOC_CMD_LEN = 4,
34 	VERR_ERSP_RATIO = 5,
35 	VERR_ASSOC_ALLOC_FAIL = 6,
36 	VERR_CONN_ALLOC_FAIL = 7,
37 	VERR_CR_CONN_LEN = 8,
38 	VERR_CR_CONN_RQST_LEN = 9,
39 	VERR_ASSOC_ID = 10,
40 	VERR_ASSOC_ID_LEN = 11,
41 	VERR_NO_ASSOC = 12,
42 	VERR_CONN_ID = 13,
43 	VERR_CONN_ID_LEN = 14,
44 	VERR_NO_CONN = 15,
45 	VERR_CR_CONN_CMD = 16,
46 	VERR_CR_CONN_CMD_LEN = 17,
47 	VERR_DISCONN_LEN = 18,
48 	VERR_DISCONN_RQST_LEN = 19,
49 	VERR_DISCONN_CMD = 20,
50 	VERR_DISCONN_CMD_LEN = 21,
51 	VERR_DISCONN_SCOPE = 22,
52 	VERR_RS_LEN = 23,
53 	VERR_RS_RQST_LEN = 24,
54 	VERR_RS_CMD = 25,
55 	VERR_RS_CMD_LEN = 26,
56 	VERR_RS_RCTL = 27,
57 	VERR_RS_RO = 28,
58 	VERR_CONN_TOO_MANY = 29,
59 	VERR_SUBNQN = 30,
60 	VERR_HOSTNQN = 31,
61 	VERR_SQSIZE = 32,
62 	VERR_NO_RPORT = 33,
63 	VERR_SUBLISTENER = 34,
64 };
65 
66 static char *validation_errors[] = {
67 	"OK",
68 	"Bad CR_ASSOC Length",
69 	"Bad CR_ASSOC Rqst Length",
70 	"Not CR_ASSOC Cmd",
71 	"Bad CR_ASSOC Cmd Length",
72 	"Bad Ersp Ratio",
73 	"Association Allocation Failed",
74 	"Queue Allocation Failed",
75 	"Bad CR_CONN Length",
76 	"Bad CR_CONN Rqst Length",
77 	"Not Association ID",
78 	"Bad Association ID Length",
79 	"No Association",
80 	"Not Connection ID",
81 	"Bad Connection ID Length",
82 	"No Connection",
83 	"Not CR_CONN Cmd",
84 	"Bad CR_CONN Cmd Length",
85 	"Bad DISCONN Length",
86 	"Bad DISCONN Rqst Length",
87 	"Not DISCONN Cmd",
88 	"Bad DISCONN Cmd Length",
89 	"Bad Disconnect Scope",
90 	"Bad RS Length",
91 	"Bad RS Rqst Length",
92 	"Not RS Cmd",
93 	"Bad RS Cmd Length",
94 	"Bad RS R_CTL",
95 	"Bad RS Relative Offset",
96 	"Too many connections for association",
97 	"Invalid subnqn or subsystem not found",
98 	"Invalid hostnqn or subsystem doesn't allow host",
99 	"SQ size = 0 or too big",
100 	"No Remote Port",
101 	"Bad Subsystem Port",
102 };
103 
104 static inline void nvmf_fc_add_assoc_to_tgt_port(struct spdk_nvmf_fc_nport *tgtport,
105 		struct spdk_nvmf_fc_association *assoc,
106 		struct spdk_nvmf_fc_remote_port_info *rport);
107 
108 static void nvmf_fc_del_connection(struct spdk_nvmf_fc_association *assoc,
109 				   struct spdk_nvmf_fc_conn *fc_conn);
110 
111 static inline FCNVME_BE32
112 cpu_to_be32(uint32_t in)
113 {
114 	uint32_t t;
115 
116 	to_be32(&t, in);
117 	return (FCNVME_BE32)t;
118 }
119 
120 static inline FCNVME_BE32
121 nvmf_fc_lsdesc_len(size_t sz)
122 {
123 	uint32_t t;
124 
125 	to_be32(&t, sz - (2 * sizeof(uint32_t)));
126 	return (FCNVME_BE32)t;
127 }
128 
129 static void
130 nvmf_fc_ls_format_rsp_hdr(void *buf, uint8_t ls_cmd, uint32_t desc_len,
131 			  uint8_t rqst_ls_cmd)
132 {
133 	struct spdk_nvmf_fc_ls_acc_hdr *acc_hdr = buf;
134 
135 	acc_hdr->w0.ls_cmd = ls_cmd;
136 	acc_hdr->desc_list_len = desc_len;
137 	to_be32(&acc_hdr->rqst.desc_tag, FCNVME_LSDESC_RQST);
138 	acc_hdr->rqst.desc_len =
139 		nvmf_fc_lsdesc_len(sizeof(struct spdk_nvmf_fc_lsdesc_rqst));
140 	acc_hdr->rqst.w0.ls_cmd = rqst_ls_cmd;
141 }
142 
143 static int
144 nvmf_fc_ls_format_rjt(void *buf, uint16_t buflen, uint8_t ls_cmd,
145 		      uint8_t reason, uint8_t explanation, uint8_t vendor)
146 {
147 	struct spdk_nvmf_fc_ls_rjt *rjt = buf;
148 
149 	bzero(buf, sizeof(struct spdk_nvmf_fc_ls_rjt));
150 	nvmf_fc_ls_format_rsp_hdr(buf, FCNVME_LSDESC_RQST,
151 				  nvmf_fc_lsdesc_len(sizeof(struct spdk_nvmf_fc_ls_rjt)),
152 				  ls_cmd);
153 	to_be32(&rjt->rjt.desc_tag, FCNVME_LSDESC_RJT);
154 	rjt->rjt.desc_len = nvmf_fc_lsdesc_len(sizeof(struct spdk_nvmf_fc_lsdesc_rjt));
155 	rjt->rjt.reason_code = reason;
156 	rjt->rjt.reason_explanation = explanation;
157 	rjt->rjt.vendor = vendor;
158 
159 	return sizeof(struct spdk_nvmf_fc_ls_rjt);
160 }
161 
162 /* *************************************************** */
163 /* Allocators/Deallocators (associations, connections, */
164 /* poller API data)                                    */
165 
166 static inline void
167 nvmf_fc_ls_free_association(struct spdk_nvmf_fc_association *assoc)
168 {
169 	/* free association's send disconnect buffer */
170 	if (assoc->snd_disconn_bufs) {
171 		nvmf_fc_free_srsr_bufs(assoc->snd_disconn_bufs);
172 	}
173 
174 	/* free association's connections */
175 	free(assoc->conns_buf);
176 
177 	/* free the association */
178 	free(assoc);
179 }
180 
181 static int
182 nvmf_fc_ls_alloc_connections(struct spdk_nvmf_fc_association *assoc,
183 			     struct spdk_nvmf_transport *nvmf_transport)
184 {
185 	uint32_t i;
186 	struct spdk_nvmf_fc_conn *fc_conn;
187 
188 	SPDK_DEBUGLOG(nvmf_fc_ls, "Pre-alloc %d qpairs for host NQN %s\n",
189 		      nvmf_transport->opts.max_qpairs_per_ctrlr, assoc->host_nqn);
190 
191 	/* allocate memory for all connections at once */
192 	assoc->conns_buf = calloc(nvmf_transport->opts.max_qpairs_per_ctrlr + 1,
193 				  sizeof(struct spdk_nvmf_fc_conn));
194 	if (assoc->conns_buf == NULL) {
195 		SPDK_ERRLOG("Out of memory for connections for new association\n");
196 		return -ENOMEM;
197 	}
198 
199 	for (i = 0; i < nvmf_transport->opts.max_qpairs_per_ctrlr; i++) {
200 		fc_conn = assoc->conns_buf + (i * sizeof(struct spdk_nvmf_fc_conn));
201 		TAILQ_INSERT_TAIL(&assoc->avail_fc_conns, fc_conn, assoc_avail_link);
202 	}
203 
204 	return 0;
205 }
206 
207 static struct spdk_nvmf_fc_association *
208 nvmf_fc_ls_new_association(uint32_t s_id,
209 			   struct spdk_nvmf_fc_nport *tgtport,
210 			   struct spdk_nvmf_fc_remote_port_info *rport,
211 			   struct spdk_nvmf_fc_lsdesc_cr_assoc_cmd *a_cmd,
212 			   struct spdk_nvmf_subsystem *subsys,
213 			   uint16_t rpi,
214 			   struct spdk_nvmf_transport *nvmf_transport)
215 {
216 	struct spdk_nvmf_fc_association *assoc;
217 	int rc;
218 
219 	SPDK_DEBUGLOG(nvmf_fc_ls,
220 		      "New Association request for port %d nport %d rpi 0x%x\n",
221 		      tgtport->fc_port->port_hdl, tgtport->nport_hdl, rpi);
222 
223 	assert(rport);
224 	if (!rport) {
225 		SPDK_ERRLOG("rport is null.\n");
226 		return NULL;
227 	}
228 
229 	assoc = calloc(1, sizeof(struct spdk_nvmf_fc_association));
230 	if (!assoc) {
231 		SPDK_ERRLOG("unable to allocate memory for new association\n");
232 		return NULL;
233 	}
234 
235 	/* initialize association */
236 #if (NVMF_FC_LS_SEND_LS_DISCONNECT == 1)
237 	/* allocate buffers to send LS disconnect command to host */
238 	assoc->snd_disconn_bufs =
239 		nvmf_fc_alloc_srsr_bufs(sizeof(struct spdk_nvmf_fc_ls_disconnect_rqst),
240 					sizeof(struct spdk_nvmf_fc_ls_rjt));
241 	if (!assoc->snd_disconn_bufs) {
242 		SPDK_ERRLOG("no dma memory for association's ls disconnect bufs\n");
243 		free(assoc);
244 		return NULL;
245 	}
246 
247 	assoc->snd_disconn_bufs->rpi = rpi;
248 #endif
249 	assoc->s_id = s_id;
250 	assoc->tgtport = tgtport;
251 	assoc->rport = rport;
252 	assoc->subsystem = subsys;
253 	assoc->nvmf_transport = nvmf_transport;
254 	assoc->assoc_state = SPDK_NVMF_FC_OBJECT_CREATED;
255 	memcpy(assoc->host_id, a_cmd->hostid, FCNVME_ASSOC_HOSTID_LEN);
256 	memcpy(assoc->host_nqn, a_cmd->hostnqn, SPDK_NVME_NQN_FIELD_SIZE);
257 	memcpy(assoc->sub_nqn, a_cmd->subnqn, SPDK_NVME_NQN_FIELD_SIZE);
258 	TAILQ_INIT(&assoc->fc_conns);
259 	TAILQ_INIT(&assoc->avail_fc_conns);
260 	assoc->ls_del_op_ctx = NULL;
261 
262 	/* allocate and assign connections for association */
263 	rc =  nvmf_fc_ls_alloc_connections(assoc, nvmf_transport);
264 	if (rc != 0) {
265 		nvmf_fc_ls_free_association(assoc);
266 		return NULL;
267 	}
268 
269 	/* add association to target port's association list */
270 	nvmf_fc_add_assoc_to_tgt_port(tgtport, assoc, rport);
271 	return assoc;
272 }
273 
274 static inline void
275 nvmf_fc_ls_append_del_cb_ctx(struct nvmf_fc_ls_op_ctx **opd_list,
276 			     struct nvmf_fc_ls_op_ctx *opd)
277 {
278 	struct nvmf_fc_ls_op_ctx *nxt;
279 
280 	if (*opd_list) {
281 		nxt = *opd_list;
282 		while (nxt->next_op_ctx) {
283 			nxt = nxt->next_op_ctx;
284 		}
285 		nxt->next_op_ctx = opd;
286 	} else {
287 		*opd_list = opd;
288 	}
289 }
290 
291 static struct spdk_nvmf_fc_conn *
292 nvmf_fc_ls_new_connection(struct spdk_nvmf_fc_association *assoc, uint16_t qid,
293 			  uint16_t esrp_ratio, uint16_t rpi, uint16_t sq_size,
294 			  struct spdk_nvmf_fc_nport *tgtport)
295 {
296 	struct spdk_nvmf_fc_conn *fc_conn;
297 
298 	fc_conn = TAILQ_FIRST(&assoc->avail_fc_conns);
299 	if (!fc_conn) {
300 		SPDK_ERRLOG("out of connections for association %p\n", assoc);
301 		return NULL;
302 	}
303 
304 	/* Remove from avail list and add to in use. */
305 	TAILQ_REMOVE(&assoc->avail_fc_conns, fc_conn, assoc_avail_link);
306 	memset(fc_conn, 0, sizeof(struct spdk_nvmf_fc_conn));
307 
308 	/* Add conn to association's connection list */
309 	TAILQ_INSERT_TAIL(&assoc->fc_conns, fc_conn, assoc_link);
310 	assoc->conn_count++;
311 
312 	if (qid == 0) {
313 		/* AdminQ connection. */
314 		assoc->aq_conn = fc_conn;
315 	}
316 
317 	fc_conn->qpair.qid = qid;
318 	fc_conn->qpair.sq_head_max = sq_size;
319 	fc_conn->qpair.state = SPDK_NVMF_QPAIR_UNINITIALIZED;
320 	fc_conn->qpair.transport = assoc->nvmf_transport;
321 	TAILQ_INIT(&fc_conn->qpair.outstanding);
322 
323 	fc_conn->conn_id = NVMF_FC_INVALID_CONN_ID;
324 	fc_conn->esrp_ratio = esrp_ratio;
325 	fc_conn->fc_assoc = assoc;
326 	fc_conn->s_id = assoc->s_id;
327 	fc_conn->d_id = assoc->tgtport->d_id;
328 	fc_conn->rpi = rpi;
329 	fc_conn->max_queue_depth = sq_size + 1;
330 	fc_conn->conn_state = SPDK_NVMF_FC_OBJECT_CREATED;
331 	TAILQ_INIT(&fc_conn->in_use_reqs);
332 	TAILQ_INIT(&fc_conn->fused_waiting_queue);
333 	fc_conn->qpair_disconnect_cb_fn = NULL;
334 	fc_conn->qpair_disconnect_ctx = NULL;
335 
336 	/* save target port trid in connection (for subsystem
337 	 * listener validation in fabric connect command)
338 	 */
339 	nvmf_fc_create_trid(&fc_conn->trid, tgtport->fc_nodename.u.wwn,
340 			    tgtport->fc_portname.u.wwn);
341 
342 	return fc_conn;
343 }
344 
345 /* End - Allocators/Deallocators (associations, connections, */
346 /*       poller API data)                                    */
347 /* ********************************************************* */
348 
349 static inline struct spdk_nvmf_fc_association *
350 nvmf_fc_ls_find_assoc(struct spdk_nvmf_fc_nport *tgtport, uint64_t assoc_id)
351 {
352 	struct spdk_nvmf_fc_association *assoc = NULL;
353 
354 	TAILQ_FOREACH(assoc, &tgtport->fc_associations, link) {
355 		if (assoc->assoc_id == assoc_id) {
356 			if (assoc->assoc_state == SPDK_NVMF_FC_OBJECT_ZOMBIE) {
357 				assoc = NULL;
358 			}
359 			break;
360 		}
361 	}
362 	return assoc;
363 }
364 
365 static inline void
366 nvmf_fc_add_assoc_to_tgt_port(struct spdk_nvmf_fc_nport *tgtport,
367 			      struct spdk_nvmf_fc_association *assoc,
368 			      struct spdk_nvmf_fc_remote_port_info *rport)
369 {
370 	TAILQ_INSERT_TAIL(&tgtport->fc_associations, assoc, link);
371 	tgtport->assoc_count++;
372 	rport->assoc_count++;
373 }
374 
375 static inline void
376 nvmf_fc_del_assoc_from_tgt_port(struct spdk_nvmf_fc_association *assoc)
377 {
378 	struct spdk_nvmf_fc_nport *tgtport = assoc->tgtport;
379 
380 	TAILQ_REMOVE(&tgtport->fc_associations, assoc, link);
381 	tgtport->assoc_count--;
382 	assoc->rport->assoc_count--;
383 }
384 
385 static void
386 nvmf_fc_do_del_conn_cbs(struct nvmf_fc_ls_op_ctx *opd,
387 			int ret)
388 {
389 	SPDK_DEBUGLOG(nvmf_fc_ls,
390 		      "performing delete conn. callbacks\n");
391 	while (opd) {
392 		struct nvmf_fc_ls_op_ctx *nxt = opd->next_op_ctx;
393 		struct spdk_nvmf_fc_ls_del_conn_api_data *dp = &opd->u.del_conn;
394 
395 		if (dp->ls_rqst) {
396 			if (nvmf_fc_xmt_ls_rsp(dp->ls_rqst->nport, dp->ls_rqst) != 0) {
397 				SPDK_ERRLOG("Send LS response for delete connection failed\n");
398 			}
399 		}
400 		if (dp->del_conn_cb) {
401 			dp->del_conn_cb(dp->del_conn_cb_data);
402 		}
403 		free(opd);
404 		opd = nxt;
405 	}
406 }
407 
408 static void
409 nvmf_fc_ls_poller_delete_conn_cb(void *cb_data, enum spdk_nvmf_fc_poller_api_ret ret)
410 {
411 	struct nvmf_fc_ls_op_ctx *opd =
412 		(struct nvmf_fc_ls_op_ctx *)cb_data;
413 	struct spdk_nvmf_fc_ls_del_conn_api_data *dp = &opd->u.del_conn;
414 	struct spdk_nvmf_fc_conn *fc_conn = dp->args.fc_conn;
415 	struct spdk_nvmf_fc_association *assoc = fc_conn->fc_assoc;
416 	struct nvmf_fc_ls_op_ctx *opd_list = (struct nvmf_fc_ls_op_ctx *)fc_conn->ls_del_op_ctx;
417 
418 	SPDK_DEBUGLOG(nvmf_fc_ls, "Poller Delete connection callback "
419 		      "for assoc_id 0x%lx conn_id 0x%lx\n", assoc->assoc_id,
420 		      fc_conn->conn_id);
421 
422 	nvmf_fc_del_connection(assoc, fc_conn);
423 	nvmf_fc_do_del_conn_cbs(opd_list, 0);
424 }
425 
426 static int
427 nvmf_fc_ls_poller_delete_conn(struct spdk_nvmf_fc_conn *fc_conn, bool send_abts,
428 			      struct spdk_nvmf_fc_ls_rqst *ls_rqst, bool backend_initiated,
429 			      spdk_nvmf_fc_del_conn_cb cb_fn, void *cb_data)
430 {
431 	struct spdk_nvmf_fc_association *assoc = fc_conn->fc_assoc;
432 	struct spdk_nvmf_fc_ls_del_conn_api_data *api_data;
433 	struct nvmf_fc_ls_op_ctx *opd = NULL;
434 
435 	SPDK_DEBUGLOG(nvmf_fc_ls, "Poller Delete connection "
436 		      "for assoc_id 0x%lx conn_id 0x%lx\n", assoc->assoc_id,
437 		      fc_conn->conn_id);
438 
439 	/* create context for delete connection API */
440 	opd = calloc(1, sizeof(struct nvmf_fc_ls_op_ctx));
441 	if (!opd) {
442 		SPDK_ERRLOG("Mem alloc failed for del conn op data");
443 		return -ENOMEM;
444 	}
445 
446 	api_data = &opd->u.del_conn;
447 	api_data->assoc = assoc;
448 	api_data->ls_rqst = ls_rqst;
449 	api_data->del_conn_cb = cb_fn;
450 	api_data->del_conn_cb_data = cb_data;
451 	api_data->aq_conn = (assoc->aq_conn == fc_conn ? true : false);
452 	api_data->args.fc_conn = fc_conn;
453 	api_data->args.send_abts = send_abts;
454 	api_data->args.backend_initiated = backend_initiated;
455 	api_data->args.hwqp = fc_conn->hwqp;
456 	api_data->args.cb_info.cb_thread = spdk_get_thread();
457 	api_data->args.cb_info.cb_func = nvmf_fc_ls_poller_delete_conn_cb;
458 	api_data->args.cb_info.cb_data = opd;
459 
460 	nvmf_fc_ls_append_del_cb_ctx((struct nvmf_fc_ls_op_ctx **) &fc_conn->ls_del_op_ctx, opd);
461 
462 	assert(fc_conn->conn_state != SPDK_NVMF_FC_OBJECT_ZOMBIE);
463 	if (fc_conn->conn_state == SPDK_NVMF_FC_OBJECT_CREATED) {
464 		fc_conn->conn_state = SPDK_NVMF_FC_OBJECT_TO_BE_DELETED;
465 		nvmf_fc_poller_api_func(api_data->args.hwqp,
466 					SPDK_NVMF_FC_POLLER_API_DEL_CONNECTION,
467 					&api_data->args);
468 	}
469 
470 	return 0;
471 }
472 
473 /* callback from poller's ADD_Connection event */
474 static void
475 nvmf_fc_ls_add_conn_cb(void *cb_data, enum spdk_nvmf_fc_poller_api_ret ret)
476 {
477 	struct nvmf_fc_ls_op_ctx *opd =
478 		(struct nvmf_fc_ls_op_ctx *)cb_data;
479 	struct spdk_nvmf_fc_ls_add_conn_api_data *dp = &opd->u.add_conn;
480 	struct spdk_nvmf_fc_association *assoc = dp->assoc;
481 	struct spdk_nvmf_fc_nport *tgtport = assoc->tgtport;
482 	struct spdk_nvmf_fc_conn *fc_conn = dp->args.fc_conn;
483 	struct spdk_nvmf_fc_ls_rqst *ls_rqst = dp->ls_rqst;
484 
485 	SPDK_DEBUGLOG(nvmf_fc_ls,
486 		      "add_conn_cb: assoc_id = 0x%lx, conn_id = 0x%lx\n",
487 		      assoc->assoc_id, fc_conn->conn_id);
488 
489 	fc_conn->create_opd = NULL;
490 
491 	if (assoc->assoc_state == SPDK_NVMF_FC_OBJECT_TO_BE_DELETED) {
492 		/* association is already being deleted - don't continue */
493 		free(opd);
494 		return;
495 	}
496 
497 	if (dp->aq_conn) {
498 		struct spdk_nvmf_fc_ls_cr_assoc_acc *assoc_acc =
499 			(struct spdk_nvmf_fc_ls_cr_assoc_acc *)ls_rqst->rspbuf.virt;
500 		/* put connection and association ID in response */
501 		to_be64(&assoc_acc->conn_id.connection_id, fc_conn->conn_id);
502 		assoc_acc->assoc_id.association_id = assoc_acc->conn_id.connection_id;
503 	} else {
504 		struct spdk_nvmf_fc_ls_cr_conn_acc *conn_acc =
505 			(struct spdk_nvmf_fc_ls_cr_conn_acc *)ls_rqst->rspbuf.virt;
506 		/* put connection ID in response */
507 		to_be64(&conn_acc->conn_id.connection_id, fc_conn->conn_id);
508 	}
509 
510 	/* send LS response */
511 	if (nvmf_fc_xmt_ls_rsp(tgtport, ls_rqst) != 0) {
512 		SPDK_ERRLOG("Send LS response for %s failed - cleaning up\n",
513 			    dp->aq_conn ? "association" : "connection");
514 		nvmf_fc_ls_poller_delete_conn(fc_conn, false, NULL, false, NULL, NULL);
515 	} else {
516 		SPDK_DEBUGLOG(nvmf_fc_ls,
517 			      "LS response (conn_id 0x%lx) sent\n", fc_conn->conn_id);
518 	}
519 
520 	free(opd);
521 }
522 
523 void
524 nvmf_fc_ls_add_conn_failure(
525 	struct spdk_nvmf_fc_association *assoc,
526 	struct spdk_nvmf_fc_ls_rqst *ls_rqst,
527 	struct spdk_nvmf_fc_conn *fc_conn,
528 	bool aq_conn)
529 {
530 	struct spdk_nvmf_fc_ls_cr_assoc_rqst *rqst;
531 	struct spdk_nvmf_fc_ls_cr_assoc_acc *acc;
532 	struct spdk_nvmf_fc_nport *tgtport = assoc->tgtport;
533 
534 	if (fc_conn->create_opd) {
535 		free(fc_conn->create_opd);
536 		fc_conn->create_opd = NULL;
537 	}
538 
539 	rqst	 = (struct spdk_nvmf_fc_ls_cr_assoc_rqst *)ls_rqst->rqstbuf.virt;
540 	acc	 = (struct spdk_nvmf_fc_ls_cr_assoc_acc *)ls_rqst->rspbuf.virt;
541 
542 	/* send failure response */
543 	ls_rqst->rsp_len = nvmf_fc_ls_format_rjt(acc,
544 			   FCNVME_MAX_LS_BUFFER_SIZE, rqst->w0.ls_cmd,
545 			   FCNVME_RJT_RC_INSUFF_RES,
546 			   FCNVME_RJT_EXP_NONE, 0);
547 
548 	nvmf_fc_xmt_ls_rsp(tgtport, ls_rqst);
549 	nvmf_fc_del_connection(assoc, fc_conn);
550 }
551 
552 
553 static void
554 nvmf_fc_ls_add_conn_to_poller(
555 	struct spdk_nvmf_fc_association *assoc,
556 	struct spdk_nvmf_fc_ls_rqst *ls_rqst,
557 	struct spdk_nvmf_fc_conn *fc_conn,
558 	bool aq_conn)
559 {
560 	struct nvmf_fc_ls_op_ctx *opd;
561 	struct spdk_nvmf_fc_ls_add_conn_api_data *api_data;
562 
563 	SPDK_DEBUGLOG(nvmf_fc_ls, "Add Connection to poller for "
564 		      "assoc_id 0x%lx conn_id 0x%lx\n", assoc->assoc_id,
565 		      fc_conn->conn_id);
566 
567 	/* Create fc_req pool for this connection */
568 	if (nvmf_fc_create_conn_reqpool(fc_conn)) {
569 		SPDK_ERRLOG("allocate fc_req pool failed\n");
570 		goto error;
571 	}
572 
573 	opd = calloc(1, sizeof(struct nvmf_fc_ls_op_ctx));
574 	if (!opd) {
575 		SPDK_ERRLOG("allocate api data for add conn op failed\n");
576 		goto error;
577 	}
578 
579 	api_data = &opd->u.add_conn;
580 
581 	api_data->args.fc_conn = fc_conn;
582 	api_data->args.cb_info.cb_thread = spdk_get_thread();
583 	api_data->args.cb_info.cb_func = nvmf_fc_ls_add_conn_cb;
584 	api_data->args.cb_info.cb_data = (void *)opd;
585 	api_data->assoc = assoc;
586 	api_data->ls_rqst = ls_rqst;
587 	api_data->aq_conn = aq_conn;
588 
589 	SPDK_DEBUGLOG(nvmf_fc_ls,
590 		      "New QP callback called.\n");
591 
592 	/* Let the nvmf_tgt decide which pollgroup to use. */
593 	fc_conn->create_opd = opd;
594 	spdk_nvmf_tgt_new_qpair(ls_rqst->nvmf_tgt, &fc_conn->qpair);
595 	return;
596 error:
597 	nvmf_fc_ls_add_conn_failure(assoc, ls_rqst, fc_conn, aq_conn);
598 }
599 
600 /* Delete association functions */
601 
602 static void
603 nvmf_fc_do_del_assoc_cbs(struct nvmf_fc_ls_op_ctx *opd, int ret)
604 {
605 	struct nvmf_fc_ls_op_ctx *nxt;
606 	struct spdk_nvmf_fc_delete_assoc_api_data *dp;
607 
608 	while (opd) {
609 		dp = &opd->u.del_assoc;
610 
611 		SPDK_DEBUGLOG(nvmf_fc_ls, "performing delete assoc. callback\n");
612 		dp->del_assoc_cb(dp->del_assoc_cb_data, ret);
613 
614 		nxt = opd->next_op_ctx;
615 		free(opd);
616 		opd = nxt;
617 	}
618 }
619 
620 static void
621 nvmf_fs_send_ls_disconnect_cb(void *hwqp, int32_t status, void *args)
622 {
623 	if (args) {
624 		SPDK_DEBUGLOG(nvmf_fc_ls, "free disconnect buffers\n");
625 		nvmf_fc_free_srsr_bufs((struct spdk_nvmf_fc_srsr_bufs *)args);
626 	}
627 }
628 
629 static void
630 nvmf_fc_del_connection(struct spdk_nvmf_fc_association *assoc,
631 		       struct spdk_nvmf_fc_conn *fc_conn)
632 {
633 	/* Free connection specific fc_req pool */
634 	nvmf_fc_free_conn_reqpool(fc_conn);
635 
636 	/* remove connection from association's connection list */
637 	TAILQ_REMOVE(&assoc->fc_conns, fc_conn, assoc_link);
638 
639 	/* Give back connection to association's free pool */
640 	TAILQ_INSERT_TAIL(&assoc->avail_fc_conns, fc_conn, assoc_avail_link);
641 
642 	fc_conn->conn_state = SPDK_NVMF_FC_OBJECT_ZOMBIE;
643 	fc_conn->ls_del_op_ctx = NULL;
644 
645 	if (--assoc->conn_count == 0) {
646 		/* last connection - remove association from target port's association list */
647 		struct nvmf_fc_ls_op_ctx *cb_opd = (struct nvmf_fc_ls_op_ctx *)assoc->ls_del_op_ctx;
648 
649 		SPDK_DEBUGLOG(nvmf_fc_ls,
650 			      "remove assoc. %lx\n", assoc->assoc_id);
651 		nvmf_fc_del_assoc_from_tgt_port(assoc);
652 
653 		if (assoc->snd_disconn_bufs &&
654 		    assoc->tgtport->fc_port->hw_port_status == SPDK_FC_PORT_ONLINE) {
655 
656 			struct spdk_nvmf_fc_ls_disconnect_rqst *dc_rqst;
657 			struct spdk_nvmf_fc_srsr_bufs *srsr_bufs;
658 
659 			dc_rqst = (struct spdk_nvmf_fc_ls_disconnect_rqst *)
660 				  assoc->snd_disconn_bufs->rqst;
661 
662 			bzero(dc_rqst, sizeof(struct spdk_nvmf_fc_ls_disconnect_rqst));
663 
664 			/* fill in request descriptor */
665 			dc_rqst->w0.ls_cmd = FCNVME_LS_DISCONNECT;
666 			to_be32(&dc_rqst->desc_list_len,
667 				sizeof(struct spdk_nvmf_fc_ls_disconnect_rqst) -
668 				(2 * sizeof(uint32_t)));
669 
670 			/* fill in disconnect command descriptor */
671 			to_be32(&dc_rqst->disconn_cmd.desc_tag, FCNVME_LSDESC_DISCONN_CMD);
672 			to_be32(&dc_rqst->disconn_cmd.desc_len,
673 				sizeof(struct spdk_nvmf_fc_lsdesc_disconn_cmd) -
674 				(2 * sizeof(uint32_t)));
675 
676 			/* fill in association id descriptor */
677 			to_be32(&dc_rqst->assoc_id.desc_tag, FCNVME_LSDESC_ASSOC_ID),
678 				to_be32(&dc_rqst->assoc_id.desc_len,
679 					sizeof(struct spdk_nvmf_fc_lsdesc_assoc_id) -
680 					(2 * sizeof(uint32_t)));
681 			to_be64(&dc_rqst->assoc_id.association_id, assoc->assoc_id);
682 
683 			srsr_bufs = assoc->snd_disconn_bufs;
684 			assoc->snd_disconn_bufs = NULL;
685 
686 			SPDK_DEBUGLOG(nvmf_fc_ls, "Send LS disconnect\n");
687 			if (nvmf_fc_xmt_srsr_req(&assoc->tgtport->fc_port->ls_queue,
688 						 srsr_bufs, nvmf_fs_send_ls_disconnect_cb,
689 						 (void *)srsr_bufs)) {
690 				SPDK_ERRLOG("Error sending LS disconnect\n");
691 				assoc->snd_disconn_bufs = srsr_bufs;
692 			}
693 		}
694 
695 		nvmf_fc_ls_free_association(assoc);
696 
697 		/* perform callbacks to all callers to delete association */
698 		nvmf_fc_do_del_assoc_cbs(cb_opd, 0);
699 	}
700 }
701 
702 /* Disconnect/delete (association) request functions */
703 
704 static int
705 _nvmf_fc_delete_association(struct spdk_nvmf_fc_nport *tgtport,
706 			    uint64_t assoc_id, bool send_abts, bool backend_initiated,
707 			    spdk_nvmf_fc_del_assoc_cb del_assoc_cb,
708 			    void *cb_data, bool from_ls_rqst)
709 {
710 	int rc;
711 	struct nvmf_fc_ls_op_ctx *opd;
712 	struct spdk_nvmf_fc_delete_assoc_api_data *api_data;
713 	struct spdk_nvmf_fc_conn *fc_conn;
714 	struct spdk_nvmf_fc_association *assoc =
715 		nvmf_fc_ls_find_assoc(tgtport, assoc_id);
716 	enum spdk_nvmf_fc_object_state assoc_state;
717 
718 	SPDK_DEBUGLOG(nvmf_fc_ls, "Delete association, "
719 		      "assoc_id 0x%lx\n", assoc_id);
720 
721 	if (!assoc) {
722 		SPDK_ERRLOG("Delete association failed: %s\n",
723 			    validation_errors[VERR_NO_ASSOC]);
724 		return VERR_NO_ASSOC;
725 	}
726 
727 	/* create cb context to put in association's list of
728 	 * callbacks to call when delete association is done */
729 	opd = calloc(1, sizeof(struct nvmf_fc_ls_op_ctx));
730 	if (!opd) {
731 		SPDK_ERRLOG("Mem alloc failed for del assoc cb data");
732 		return -ENOMEM;
733 	}
734 
735 	api_data = &opd->u.del_assoc;
736 	api_data->assoc = assoc;
737 	api_data->from_ls_rqst = from_ls_rqst;
738 	api_data->del_assoc_cb = del_assoc_cb;
739 	api_data->del_assoc_cb_data = cb_data;
740 	api_data->args.cb_info.cb_data = opd;
741 	nvmf_fc_ls_append_del_cb_ctx((struct nvmf_fc_ls_op_ctx **) &assoc->ls_del_op_ctx, opd);
742 
743 	assoc_state = assoc->assoc_state;
744 	if (assoc_state == SPDK_NVMF_FC_OBJECT_TO_BE_DELETED) {
745 		/* association already being deleted */
746 		return 0;
747 	}
748 
749 	/* mark assoc. to be deleted */
750 	assoc->assoc_state = SPDK_NVMF_FC_OBJECT_TO_BE_DELETED;
751 
752 	/* delete all of the association's connections */
753 	TAILQ_FOREACH(fc_conn, &assoc->fc_conns, assoc_link) {
754 		rc = nvmf_fc_ls_poller_delete_conn(fc_conn, send_abts, NULL, backend_initiated, NULL, NULL);
755 		if (rc) {
756 			SPDK_ERRLOG("Delete connection failed for assoc_id 0x%lx conn_id 0x%lx\n",
757 				    assoc->assoc_id, fc_conn->conn_id);
758 			return rc;
759 		}
760 	}
761 
762 	return 0;
763 }
764 
765 static void
766 nvmf_fc_ls_disconnect_assoc_cb(void *cb_data, uint32_t err)
767 {
768 	struct nvmf_fc_ls_op_ctx *opd = (struct nvmf_fc_ls_op_ctx *)cb_data;
769 	struct spdk_nvmf_fc_ls_disconn_assoc_api_data *dp = &opd->u.disconn_assoc;
770 	struct spdk_nvmf_fc_nport *tgtport = dp->tgtport;
771 	struct spdk_nvmf_fc_ls_rqst *ls_rqst = dp->ls_rqst;
772 
773 	SPDK_DEBUGLOG(nvmf_fc_ls, "Disconnect association callback begin "
774 		      "nport %d\n", tgtport->nport_hdl);
775 	if (err != 0) {
776 		/* send failure response */
777 		struct spdk_nvmf_fc_ls_cr_assoc_rqst *rqst =
778 			(struct spdk_nvmf_fc_ls_cr_assoc_rqst *)ls_rqst->rqstbuf.virt;
779 		struct spdk_nvmf_fc_ls_cr_assoc_acc *acc =
780 			(struct spdk_nvmf_fc_ls_cr_assoc_acc *)ls_rqst->rspbuf.virt;
781 		ls_rqst->rsp_len = nvmf_fc_ls_format_rjt(acc,
782 				   FCNVME_MAX_LS_BUFFER_SIZE,
783 				   rqst->w0.ls_cmd,
784 				   FCNVME_RJT_RC_UNAB,
785 				   FCNVME_RJT_EXP_NONE,
786 				   0);
787 	}
788 
789 	nvmf_fc_xmt_ls_rsp(tgtport, ls_rqst);
790 
791 	free(opd);
792 	SPDK_DEBUGLOG(nvmf_fc_ls, "Disconnect association callback complete "
793 		      "nport %d err %d\n", tgtport->nport_hdl, err);
794 }
795 
796 static void
797 nvmf_fc_ls_disconnect_assoc(struct spdk_nvmf_fc_nport *tgtport,
798 			    struct spdk_nvmf_fc_ls_rqst *ls_rqst, uint64_t assoc_id)
799 {
800 	struct nvmf_fc_ls_op_ctx *opd;
801 	struct spdk_nvmf_fc_ls_cr_assoc_rqst *rqst =
802 		(struct spdk_nvmf_fc_ls_cr_assoc_rqst *)ls_rqst->rqstbuf.virt;
803 	struct spdk_nvmf_fc_ls_cr_assoc_acc *acc =
804 		(struct spdk_nvmf_fc_ls_cr_assoc_acc *)ls_rqst->rspbuf.virt;
805 	struct spdk_nvmf_fc_ls_disconn_assoc_api_data *api_data;
806 	int ret;
807 	uint8_t reason = 0;
808 
809 	opd = calloc(1, sizeof(struct nvmf_fc_ls_op_ctx));
810 	if (!opd) {
811 		/* send failure response */
812 		SPDK_ERRLOG("Allocate disconn assoc op data failed\n");
813 		reason = FCNVME_RJT_RC_INSUFF_RES;
814 		goto send_rjt;
815 	}
816 
817 	api_data = &opd->u.disconn_assoc;
818 	api_data->tgtport = tgtport;
819 	api_data->ls_rqst = ls_rqst;
820 	ret = _nvmf_fc_delete_association(tgtport, assoc_id,
821 					  false, false,
822 					  nvmf_fc_ls_disconnect_assoc_cb,
823 					  api_data, true);
824 	if (!ret) {
825 		return;
826 	}
827 
828 	/* delete association failed */
829 	switch (ret) {
830 	case VERR_NO_ASSOC:
831 		reason = FCNVME_RJT_RC_INV_ASSOC;
832 		break;
833 	case -ENOMEM:
834 		reason = FCNVME_RJT_RC_INSUFF_RES;
835 		break;
836 	default:
837 		reason = FCNVME_RJT_RC_LOGIC;
838 	}
839 
840 	free(opd);
841 
842 send_rjt:
843 	ls_rqst->rsp_len = nvmf_fc_ls_format_rjt(acc,
844 			   FCNVME_MAX_LS_BUFFER_SIZE,
845 			   rqst->w0.ls_cmd, reason,
846 			   FCNVME_RJT_EXP_NONE, 0);
847 	nvmf_fc_xmt_ls_rsp(tgtport, ls_rqst);
848 }
849 
850 static int
851 nvmf_fc_ls_validate_host(struct spdk_nvmf_subsystem *subsystem, const char *hostnqn)
852 {
853 
854 	if (!spdk_nvmf_subsystem_host_allowed(subsystem, hostnqn)) {
855 		return -EPERM;
856 	}
857 
858 	return 0;
859 }
860 
861 /* **************************** */
862 /* LS Request Handler Functions */
863 
864 static void
865 nvmf_fc_ls_process_cass(uint32_t s_id,
866 			struct spdk_nvmf_fc_nport *tgtport,
867 			struct spdk_nvmf_fc_ls_rqst *ls_rqst)
868 {
869 	struct spdk_nvmf_fc_ls_cr_assoc_rqst *rqst =
870 		(struct spdk_nvmf_fc_ls_cr_assoc_rqst *)ls_rqst->rqstbuf.virt;
871 	struct spdk_nvmf_fc_ls_cr_assoc_acc *acc =
872 		(struct spdk_nvmf_fc_ls_cr_assoc_acc *)ls_rqst->rspbuf.virt;
873 	struct spdk_nvmf_fc_association *assoc;
874 	struct spdk_nvmf_fc_conn *fc_conn;
875 	struct spdk_nvmf_subsystem *subsystem = NULL;
876 	const char *hostnqn = (const char *)rqst->assoc_cmd.hostnqn;
877 	int errmsg_ind = 0;
878 	uint8_t rc = FCNVME_RJT_RC_NONE;
879 	uint8_t ec = FCNVME_RJT_EXP_NONE;
880 	struct spdk_nvmf_transport *transport = spdk_nvmf_tgt_get_transport(ls_rqst->nvmf_tgt,
881 						SPDK_NVME_TRANSPORT_NAME_FC);
882 
883 	SPDK_DEBUGLOG(nvmf_fc_ls,
884 		      "LS_CASS: ls_rqst_len=%d, desc_list_len=%d, cmd_len=%d, sq_size=%d, "
885 		      "Subnqn: %s, Hostnqn: %s, Tgtport nn:%lx, pn:%lx\n",
886 		      ls_rqst->rqst_len, from_be32(&rqst->desc_list_len),
887 		      from_be32(&rqst->assoc_cmd.desc_len),
888 		      from_be32(&rqst->assoc_cmd.sqsize),
889 		      rqst->assoc_cmd.subnqn, hostnqn,
890 		      tgtport->fc_nodename.u.wwn, tgtport->fc_portname.u.wwn);
891 
892 	if (ls_rqst->rqst_len < FCNVME_LS_CA_CMD_MIN_LEN) {
893 		SPDK_ERRLOG("assoc_cmd req len = %d, should be at least %d\n",
894 			    ls_rqst->rqst_len, FCNVME_LS_CA_CMD_MIN_LEN);
895 		errmsg_ind = VERR_CR_ASSOC_LEN;
896 		rc = FCNVME_RJT_RC_INV_PARAM;
897 		ec = FCNVME_RJT_EXP_INV_LEN;
898 	} else if (from_be32(&rqst->desc_list_len) <
899 		   FCNVME_LS_CA_DESC_LIST_MIN_LEN) {
900 		SPDK_ERRLOG("assoc_cmd desc list len = %d, should be at least %d\n",
901 			    from_be32(&rqst->desc_list_len),
902 			    FCNVME_LS_CA_DESC_LIST_MIN_LEN);
903 		errmsg_ind = VERR_CR_ASSOC_RQST_LEN;
904 		rc = FCNVME_RJT_RC_INV_PARAM;
905 		ec = FCNVME_RJT_EXP_INV_LEN;
906 	} else if (rqst->assoc_cmd.desc_tag !=
907 		   cpu_to_be32(FCNVME_LSDESC_CREATE_ASSOC_CMD)) {
908 		errmsg_ind = VERR_CR_ASSOC_CMD;
909 		rc = FCNVME_RJT_RC_INV_PARAM;
910 	} else if (from_be32(&rqst->assoc_cmd.desc_len) <
911 		   FCNVME_LS_CA_DESC_MIN_LEN) {
912 		SPDK_ERRLOG("assoc_cmd desc len = %d, should be at least %d\n",
913 			    from_be32(&rqst->assoc_cmd.desc_len),
914 			    FCNVME_LS_CA_DESC_MIN_LEN);
915 		errmsg_ind = VERR_CR_ASSOC_CMD_LEN;
916 		rc = FCNVME_RJT_RC_INV_PARAM;
917 		ec = FCNVME_RJT_EXP_INV_LEN;
918 	} else if (!rqst->assoc_cmd.ersp_ratio ||
919 		   (from_be16(&rqst->assoc_cmd.ersp_ratio) >=
920 		    from_be16(&rqst->assoc_cmd.sqsize))) {
921 		errmsg_ind = VERR_ERSP_RATIO;
922 		rc = FCNVME_RJT_RC_INV_PARAM;
923 		ec = FCNVME_RJT_EXP_INV_ESRP;
924 	} else if (from_be16(&rqst->assoc_cmd.sqsize) == 0 ||
925 		   from_be16(&rqst->assoc_cmd.sqsize) > transport->opts.max_aq_depth) {
926 		errmsg_ind = VERR_SQSIZE;
927 		rc = FCNVME_RJT_RC_INV_PARAM;
928 		ec = FCNVME_RJT_EXP_SQ_SIZE;
929 	}
930 
931 	if (rc != FCNVME_RJT_RC_NONE) {
932 		goto rjt_cass;
933 	}
934 
935 	subsystem = spdk_nvmf_tgt_find_subsystem(ls_rqst->nvmf_tgt, rqst->assoc_cmd.subnqn);
936 	if (subsystem == NULL) {
937 		errmsg_ind = VERR_SUBNQN;
938 		rc = FCNVME_RJT_RC_INV_PARAM;
939 		ec = FCNVME_RJT_EXP_INV_SUBNQN;
940 		goto rjt_cass;
941 	}
942 
943 	if (nvmf_fc_ls_validate_host(subsystem, hostnqn)) {
944 		errmsg_ind = VERR_HOSTNQN;
945 		rc = FCNVME_RJT_RC_INV_HOST;
946 		ec = FCNVME_RJT_EXP_INV_HOSTNQN;
947 		goto rjt_cass;
948 	}
949 
950 	/* get new association */
951 	assoc = nvmf_fc_ls_new_association(s_id, tgtport, ls_rqst->rport,
952 					   &rqst->assoc_cmd, subsystem,
953 					   ls_rqst->rpi, transport);
954 	if (!assoc) {
955 		errmsg_ind = VERR_ASSOC_ALLOC_FAIL;
956 		rc = FCNVME_RJT_RC_INSUFF_RES;
957 		ec = FCNVME_RJT_EXP_NONE;
958 		goto rjt_cass;
959 	}
960 
961 	/* alloc admin q (i.e. connection) */
962 	fc_conn = nvmf_fc_ls_new_connection(assoc, 0,
963 					    from_be16(&rqst->assoc_cmd.ersp_ratio),
964 					    ls_rqst->rpi,
965 					    from_be16(&rqst->assoc_cmd.sqsize),
966 					    tgtport);
967 	if (!fc_conn) {
968 		nvmf_fc_ls_free_association(assoc);
969 		errmsg_ind = VERR_CONN_ALLOC_FAIL;
970 		rc = FCNVME_RJT_RC_INSUFF_RES;
971 		ec = FCNVME_RJT_EXP_NONE;
972 		goto rjt_cass;
973 	}
974 
975 	/* format accept response */
976 	bzero(acc, sizeof(*acc));
977 	ls_rqst->rsp_len = sizeof(*acc);
978 
979 	nvmf_fc_ls_format_rsp_hdr(acc, FCNVME_LS_ACC,
980 				  nvmf_fc_lsdesc_len(
981 					  sizeof(struct spdk_nvmf_fc_ls_cr_assoc_acc)),
982 				  FCNVME_LS_CREATE_ASSOCIATION);
983 	to_be32(&acc->assoc_id.desc_tag, FCNVME_LSDESC_ASSOC_ID);
984 	acc->assoc_id.desc_len =
985 		nvmf_fc_lsdesc_len(sizeof(struct spdk_nvmf_fc_lsdesc_assoc_id));
986 	to_be32(&acc->conn_id.desc_tag, FCNVME_LSDESC_CONN_ID);
987 	acc->conn_id.desc_len =
988 		nvmf_fc_lsdesc_len(sizeof(struct spdk_nvmf_fc_lsdesc_conn_id));
989 
990 	/* assign connection to HWQP poller - also sends response */
991 	nvmf_fc_ls_add_conn_to_poller(assoc, ls_rqst, fc_conn, true);
992 
993 	return;
994 
995 rjt_cass:
996 	SPDK_ERRLOG("Create Association LS failed: %s\n", validation_errors[errmsg_ind]);
997 	ls_rqst->rsp_len = nvmf_fc_ls_format_rjt(acc, FCNVME_MAX_LS_BUFFER_SIZE,
998 			   rqst->w0.ls_cmd, rc, ec, 0);
999 	nvmf_fc_xmt_ls_rsp(tgtport, ls_rqst);
1000 }
1001 
1002 static void
1003 nvmf_fc_ls_process_cioc(struct spdk_nvmf_fc_nport *tgtport,
1004 			struct spdk_nvmf_fc_ls_rqst *ls_rqst)
1005 {
1006 	struct spdk_nvmf_fc_ls_cr_conn_rqst *rqst =
1007 		(struct spdk_nvmf_fc_ls_cr_conn_rqst *)ls_rqst->rqstbuf.virt;
1008 	struct spdk_nvmf_fc_ls_cr_conn_acc *acc =
1009 		(struct spdk_nvmf_fc_ls_cr_conn_acc *)ls_rqst->rspbuf.virt;
1010 	struct spdk_nvmf_fc_association *assoc;
1011 	struct spdk_nvmf_fc_conn *fc_conn = NULL;
1012 	int errmsg_ind = 0;
1013 	uint8_t rc = FCNVME_RJT_RC_NONE;
1014 	uint8_t ec = FCNVME_RJT_EXP_NONE;
1015 	struct spdk_nvmf_transport *transport = spdk_nvmf_tgt_get_transport(ls_rqst->nvmf_tgt,
1016 						SPDK_NVME_TRANSPORT_NAME_FC);
1017 
1018 	SPDK_DEBUGLOG(nvmf_fc_ls,
1019 		      "LS_CIOC: ls_rqst_len=%d, desc_list_len=%d, cmd_len=%d, "
1020 		      "assoc_id=0x%lx, sq_size=%d, esrp=%d, Tgtport nn:%lx, pn:%lx\n",
1021 		      ls_rqst->rqst_len, from_be32(&rqst->desc_list_len),
1022 		      from_be32(&rqst->connect_cmd.desc_len),
1023 		      from_be64(&rqst->assoc_id.association_id),
1024 		      from_be32(&rqst->connect_cmd.sqsize),
1025 		      from_be32(&rqst->connect_cmd.ersp_ratio),
1026 		      tgtport->fc_nodename.u.wwn, tgtport->fc_portname.u.wwn);
1027 
1028 	if (ls_rqst->rqst_len < sizeof(struct spdk_nvmf_fc_ls_cr_conn_rqst)) {
1029 		errmsg_ind = VERR_CR_CONN_LEN;
1030 		rc = FCNVME_RJT_RC_INV_PARAM;
1031 		ec = FCNVME_RJT_EXP_INV_LEN;
1032 	} else if (rqst->desc_list_len !=
1033 		   nvmf_fc_lsdesc_len(sizeof(struct spdk_nvmf_fc_ls_cr_conn_rqst))) {
1034 		errmsg_ind = VERR_CR_CONN_RQST_LEN;
1035 		rc = FCNVME_RJT_RC_INV_PARAM;
1036 		ec = FCNVME_RJT_EXP_INV_LEN;
1037 	} else if (rqst->assoc_id.desc_tag !=
1038 		   cpu_to_be32(FCNVME_LSDESC_ASSOC_ID)) {
1039 		errmsg_ind = VERR_ASSOC_ID;
1040 		rc = FCNVME_RJT_RC_INV_PARAM;
1041 	} else if (rqst->assoc_id.desc_len !=
1042 		   nvmf_fc_lsdesc_len(sizeof(struct spdk_nvmf_fc_lsdesc_assoc_id))) {
1043 		errmsg_ind = VERR_ASSOC_ID_LEN;
1044 		rc = FCNVME_RJT_RC_INV_PARAM;
1045 		ec = FCNVME_RJT_EXP_INV_LEN;
1046 	} else if (rqst->connect_cmd.desc_tag !=
1047 		   cpu_to_be32(FCNVME_LSDESC_CREATE_CONN_CMD)) {
1048 		errmsg_ind = VERR_CR_CONN_CMD;
1049 		rc = FCNVME_RJT_RC_INV_PARAM;
1050 	} else if (rqst->connect_cmd.desc_len !=
1051 		   nvmf_fc_lsdesc_len(
1052 			   sizeof(struct spdk_nvmf_fc_lsdesc_cr_conn_cmd))) {
1053 		errmsg_ind = VERR_CR_CONN_CMD_LEN;
1054 		rc = FCNVME_RJT_RC_INV_PARAM;
1055 		ec = FCNVME_RJT_EXP_INV_LEN;
1056 	} else if (!rqst->connect_cmd.ersp_ratio ||
1057 		   (from_be16(&rqst->connect_cmd.ersp_ratio) >=
1058 		    from_be16(&rqst->connect_cmd.sqsize))) {
1059 		errmsg_ind = VERR_ERSP_RATIO;
1060 		rc = FCNVME_RJT_RC_INV_PARAM;
1061 		ec = FCNVME_RJT_EXP_INV_ESRP;
1062 	} else if (from_be16(&rqst->connect_cmd.sqsize) == 0 ||
1063 		   from_be16(&rqst->connect_cmd.sqsize) > transport->opts.max_queue_depth) {
1064 		errmsg_ind = VERR_SQSIZE;
1065 		rc = FCNVME_RJT_RC_INV_PARAM;
1066 		ec = FCNVME_RJT_EXP_SQ_SIZE;
1067 	}
1068 
1069 	if (rc != FCNVME_RJT_RC_NONE) {
1070 		goto rjt_cioc;
1071 	}
1072 
1073 	/* find association */
1074 	assoc = nvmf_fc_ls_find_assoc(tgtport,
1075 				      from_be64(&rqst->assoc_id.association_id));
1076 	if (!assoc) {
1077 		errmsg_ind = VERR_NO_ASSOC;
1078 		rc = FCNVME_RJT_RC_INV_ASSOC;
1079 	} else if (assoc->assoc_state == SPDK_NVMF_FC_OBJECT_TO_BE_DELETED) {
1080 		/* association is being deleted - don't allow more connections */
1081 		errmsg_ind = VERR_NO_ASSOC;
1082 		rc = FCNVME_RJT_RC_INV_ASSOC;
1083 	} else  if (assoc->conn_count >= transport->opts.max_qpairs_per_ctrlr) {
1084 		errmsg_ind = VERR_CONN_TOO_MANY;
1085 		rc = FCNVME_RJT_RC_INV_PARAM;
1086 		ec =  FCNVME_RJT_EXP_INV_Q_ID;
1087 	}
1088 
1089 	if (rc != FCNVME_RJT_RC_NONE) {
1090 		goto rjt_cioc;
1091 	}
1092 
1093 	fc_conn = nvmf_fc_ls_new_connection(assoc, from_be16(&rqst->connect_cmd.qid),
1094 					    from_be16(&rqst->connect_cmd.ersp_ratio),
1095 					    ls_rqst->rpi,
1096 					    from_be16(&rqst->connect_cmd.sqsize),
1097 					    tgtport);
1098 	if (!fc_conn) {
1099 		errmsg_ind = VERR_CONN_ALLOC_FAIL;
1100 		rc = FCNVME_RJT_RC_INSUFF_RES;
1101 		ec = FCNVME_RJT_EXP_NONE;
1102 		goto rjt_cioc;
1103 	}
1104 
1105 	/* format accept response */
1106 	SPDK_DEBUGLOG(nvmf_fc_ls, "Formatting LS accept response for "
1107 		      "assoc_id 0x%lx conn_id 0x%lx\n", assoc->assoc_id,
1108 		      fc_conn->conn_id);
1109 	bzero(acc, sizeof(*acc));
1110 	ls_rqst->rsp_len = sizeof(*acc);
1111 	nvmf_fc_ls_format_rsp_hdr(acc, FCNVME_LS_ACC,
1112 				  nvmf_fc_lsdesc_len(
1113 					  sizeof(struct spdk_nvmf_fc_ls_cr_conn_acc)),
1114 				  FCNVME_LS_CREATE_CONNECTION);
1115 	to_be32(&acc->conn_id.desc_tag, FCNVME_LSDESC_CONN_ID);
1116 	acc->conn_id.desc_len =
1117 		nvmf_fc_lsdesc_len(sizeof(struct spdk_nvmf_fc_lsdesc_conn_id));
1118 
1119 	/* assign connection to HWQP poller - also sends response */
1120 	nvmf_fc_ls_add_conn_to_poller(assoc, ls_rqst, fc_conn, false);
1121 
1122 	return;
1123 
1124 rjt_cioc:
1125 	SPDK_ERRLOG("Create Connection LS failed: %s\n", validation_errors[errmsg_ind]);
1126 
1127 	ls_rqst->rsp_len = nvmf_fc_ls_format_rjt(acc, FCNVME_MAX_LS_BUFFER_SIZE,
1128 			   rqst->w0.ls_cmd, rc, ec, 0);
1129 	nvmf_fc_xmt_ls_rsp(tgtport, ls_rqst);
1130 }
1131 
1132 static void
1133 nvmf_fc_ls_process_disc(struct spdk_nvmf_fc_nport *tgtport,
1134 			struct spdk_nvmf_fc_ls_rqst *ls_rqst)
1135 {
1136 	struct spdk_nvmf_fc_ls_disconnect_rqst *rqst =
1137 		(struct spdk_nvmf_fc_ls_disconnect_rqst *)ls_rqst->rqstbuf.virt;
1138 	struct spdk_nvmf_fc_ls_disconnect_acc *acc =
1139 		(struct spdk_nvmf_fc_ls_disconnect_acc *)ls_rqst->rspbuf.virt;
1140 	struct spdk_nvmf_fc_association *assoc;
1141 	int errmsg_ind = 0;
1142 	uint8_t rc = FCNVME_RJT_RC_NONE;
1143 	uint8_t ec = FCNVME_RJT_EXP_NONE;
1144 
1145 	SPDK_DEBUGLOG(nvmf_fc_ls,
1146 		      "LS_DISC: ls_rqst_len=%d, desc_list_len=%d, cmd_len=%d,"
1147 		      "assoc_id=0x%lx\n",
1148 		      ls_rqst->rqst_len, from_be32(&rqst->desc_list_len),
1149 		      from_be32(&rqst->disconn_cmd.desc_len),
1150 		      from_be64(&rqst->assoc_id.association_id));
1151 
1152 	if (ls_rqst->rqst_len < sizeof(struct spdk_nvmf_fc_ls_disconnect_rqst)) {
1153 		errmsg_ind = VERR_DISCONN_LEN;
1154 		rc = FCNVME_RJT_RC_INV_PARAM;
1155 		ec = FCNVME_RJT_EXP_INV_LEN;
1156 	} else if (rqst->desc_list_len !=
1157 		   nvmf_fc_lsdesc_len(sizeof(struct spdk_nvmf_fc_ls_disconnect_rqst))) {
1158 		errmsg_ind = VERR_DISCONN_RQST_LEN;
1159 		rc = FCNVME_RJT_RC_INV_PARAM;
1160 		ec = FCNVME_RJT_EXP_INV_LEN;
1161 	} else if (rqst->assoc_id.desc_tag !=
1162 		   cpu_to_be32(FCNVME_LSDESC_ASSOC_ID)) {
1163 		errmsg_ind = VERR_ASSOC_ID;
1164 		rc = FCNVME_RJT_RC_INV_PARAM;
1165 	} else if (rqst->assoc_id.desc_len !=
1166 		   nvmf_fc_lsdesc_len(sizeof(struct spdk_nvmf_fc_lsdesc_assoc_id))) {
1167 		errmsg_ind = VERR_ASSOC_ID_LEN;
1168 		rc = FCNVME_RJT_RC_INV_PARAM;
1169 		ec = FCNVME_RJT_EXP_INV_LEN;
1170 	} else if (rqst->disconn_cmd.desc_tag !=
1171 		   cpu_to_be32(FCNVME_LSDESC_DISCONN_CMD)) {
1172 		rc = FCNVME_RJT_RC_INV_PARAM;
1173 		errmsg_ind = VERR_DISCONN_CMD;
1174 	} else if (rqst->disconn_cmd.desc_len !=
1175 		   nvmf_fc_lsdesc_len(sizeof(struct spdk_nvmf_fc_lsdesc_disconn_cmd))) {
1176 		errmsg_ind = VERR_DISCONN_CMD_LEN;
1177 		rc = FCNVME_RJT_RC_INV_PARAM;
1178 		ec = FCNVME_RJT_EXP_INV_LEN;
1179 	}
1180 
1181 	if (rc != FCNVME_RJT_RC_NONE) {
1182 		goto rjt_disc;
1183 	}
1184 
1185 	/* match an active association */
1186 	assoc = nvmf_fc_ls_find_assoc(tgtport,
1187 				      from_be64(&rqst->assoc_id.association_id));
1188 	if (!assoc) {
1189 		errmsg_ind = VERR_NO_ASSOC;
1190 		rc = FCNVME_RJT_RC_INV_ASSOC;
1191 		goto rjt_disc;
1192 	}
1193 
1194 	/* format response */
1195 	bzero(acc, sizeof(*acc));
1196 	ls_rqst->rsp_len = sizeof(*acc);
1197 
1198 	nvmf_fc_ls_format_rsp_hdr(acc, FCNVME_LS_ACC,
1199 				  nvmf_fc_lsdesc_len(
1200 					  sizeof(struct spdk_nvmf_fc_ls_disconnect_acc)),
1201 				  FCNVME_LS_DISCONNECT);
1202 
1203 	nvmf_fc_ls_disconnect_assoc(tgtport, ls_rqst, assoc->assoc_id);
1204 	return;
1205 
1206 rjt_disc:
1207 	SPDK_ERRLOG("Disconnect LS failed: %s\n", validation_errors[errmsg_ind]);
1208 	ls_rqst->rsp_len = nvmf_fc_ls_format_rjt(acc, FCNVME_MAX_LS_BUFFER_SIZE,
1209 			   rqst->w0.ls_cmd, rc, ec, 0);
1210 	nvmf_fc_xmt_ls_rsp(tgtport, ls_rqst);
1211 }
1212 
1213 /* ************************ */
1214 /* external functions       */
1215 
1216 void
1217 nvmf_fc_ls_init(struct spdk_nvmf_fc_port *fc_port)
1218 {
1219 }
1220 
1221 void
1222 nvmf_fc_ls_fini(struct spdk_nvmf_fc_port *fc_port)
1223 {
1224 }
1225 
1226 void
1227 nvmf_fc_handle_ls_rqst(struct spdk_nvmf_fc_ls_rqst *ls_rqst)
1228 {
1229 	struct spdk_nvmf_fc_ls_rqst_w0 *w0 =
1230 		(struct spdk_nvmf_fc_ls_rqst_w0 *)ls_rqst->rqstbuf.virt;
1231 	uint32_t s_id = ls_rqst->s_id;
1232 	struct spdk_nvmf_fc_nport *tgtport = ls_rqst->nport;
1233 
1234 	SPDK_DEBUGLOG(nvmf_fc_ls, "LS cmd=%d\n", w0->ls_cmd);
1235 
1236 	switch (w0->ls_cmd) {
1237 	case FCNVME_LS_CREATE_ASSOCIATION:
1238 		nvmf_fc_ls_process_cass(s_id, tgtport, ls_rqst);
1239 		break;
1240 	case FCNVME_LS_CREATE_CONNECTION:
1241 		nvmf_fc_ls_process_cioc(tgtport, ls_rqst);
1242 		break;
1243 	case FCNVME_LS_DISCONNECT:
1244 		nvmf_fc_ls_process_disc(tgtport, ls_rqst);
1245 		break;
1246 	default:
1247 		SPDK_ERRLOG("Invalid LS cmd=%d\n", w0->ls_cmd);
1248 		ls_rqst->rsp_len = nvmf_fc_ls_format_rjt(ls_rqst->rspbuf.virt,
1249 				   FCNVME_MAX_LS_BUFFER_SIZE, w0->ls_cmd,
1250 				   FCNVME_RJT_RC_INVAL, FCNVME_RJT_EXP_NONE, 0);
1251 		nvmf_fc_xmt_ls_rsp(tgtport, ls_rqst);
1252 	}
1253 }
1254 
1255 int
1256 nvmf_fc_delete_association(struct spdk_nvmf_fc_nport *tgtport,
1257 			   uint64_t assoc_id, bool send_abts, bool backend_initiated,
1258 			   spdk_nvmf_fc_del_assoc_cb del_assoc_cb,
1259 			   void *cb_data)
1260 {
1261 	return _nvmf_fc_delete_association(tgtport, assoc_id, send_abts, backend_initiated,
1262 					   del_assoc_cb, cb_data, false);
1263 }
1264 
1265 int
1266 nvmf_fc_delete_connection(struct spdk_nvmf_fc_conn *fc_conn, bool send_abts,
1267 			  bool backend_initiated, spdk_nvmf_fc_del_conn_cb cb_fn,
1268 			  void *cb_data)
1269 {
1270 	return nvmf_fc_ls_poller_delete_conn(fc_conn, send_abts, NULL,
1271 					     backend_initiated, cb_fn, cb_data);
1272 }
1273 
1274 
1275 static void
1276 nvmf_fc_poller_api_cb_event(void *arg)
1277 {
1278 	struct spdk_nvmf_fc_poller_api_cb_info *cb_info =
1279 		(struct spdk_nvmf_fc_poller_api_cb_info *) arg;
1280 
1281 	assert(cb_info != NULL);
1282 	cb_info->cb_func(cb_info->cb_data, cb_info->ret);
1283 }
1284 
1285 static void
1286 nvmf_fc_poller_api_perform_cb(struct spdk_nvmf_fc_poller_api_cb_info *cb_info,
1287 			      enum spdk_nvmf_fc_poller_api_ret ret)
1288 {
1289 	if (cb_info->cb_func && cb_info->cb_thread) {
1290 		cb_info->ret = ret;
1291 		/* callback to main thread */
1292 		spdk_thread_send_msg(cb_info->cb_thread, nvmf_fc_poller_api_cb_event,
1293 				     (void *) cb_info);
1294 	}
1295 }
1296 
1297 static int
1298 nvmf_fc_poller_add_conn_lookup_data(struct spdk_nvmf_fc_hwqp *hwqp,
1299 				    struct spdk_nvmf_fc_conn *fc_conn)
1300 {
1301 	int rc = -1;
1302 	struct spdk_nvmf_fc_hwqp_rport *rport = NULL;
1303 
1304 	/* Add connection based lookup entry. */
1305 	rc = rte_hash_add_key_data(hwqp->connection_list_hash,
1306 				   (void *)&fc_conn->conn_id, (void *)fc_conn);
1307 
1308 	if (rc < 0) {
1309 		SPDK_ERRLOG("Failed to add connection hash entry\n");
1310 		return rc;
1311 	}
1312 
1313 	/* RPI based lookup */
1314 	if (rte_hash_lookup_data(hwqp->rport_list_hash, (void *)&fc_conn->rpi, (void **)&rport) < 0) {
1315 		rport = calloc(1, sizeof(struct spdk_nvmf_fc_hwqp_rport));
1316 		if (!rport) {
1317 			SPDK_ERRLOG("Failed to allocate rport entry\n");
1318 			rc = -ENOMEM;
1319 			goto del_conn_hash;
1320 		}
1321 
1322 		/* Add rport table entry */
1323 		rc = rte_hash_add_key_data(hwqp->rport_list_hash,
1324 					   (void *)&fc_conn->rpi, (void *)rport);
1325 		if (rc < 0) {
1326 			SPDK_ERRLOG("Failed to add rport hash entry\n");
1327 			goto del_rport;
1328 		}
1329 		TAILQ_INIT(&rport->conn_list);
1330 	}
1331 
1332 	/* Add to rport conn list */
1333 	TAILQ_INSERT_TAIL(&rport->conn_list, fc_conn, rport_link);
1334 	return 0;
1335 
1336 del_rport:
1337 	free(rport);
1338 del_conn_hash:
1339 	rte_hash_del_key(hwqp->connection_list_hash, (void *)&fc_conn->conn_id);
1340 	return rc;
1341 }
1342 
1343 static void
1344 nvmf_fc_poller_del_conn_lookup_data(struct spdk_nvmf_fc_hwqp *hwqp,
1345 				    struct spdk_nvmf_fc_conn *fc_conn)
1346 {
1347 	struct spdk_nvmf_fc_hwqp_rport *rport = NULL;
1348 
1349 	if (rte_hash_del_key(hwqp->connection_list_hash, (void *)&fc_conn->conn_id) < 0) {
1350 		SPDK_ERRLOG("Failed to del connection(%lx) hash entry\n",
1351 			    fc_conn->conn_id);
1352 	}
1353 
1354 	if (rte_hash_lookup_data(hwqp->rport_list_hash, (void *)&fc_conn->rpi, (void **)&rport) >= 0) {
1355 		TAILQ_REMOVE(&rport->conn_list, fc_conn, rport_link);
1356 
1357 		/* If last conn del rpi hash */
1358 		if (TAILQ_EMPTY(&rport->conn_list)) {
1359 			if (rte_hash_del_key(hwqp->rport_list_hash, (void *)&fc_conn->rpi) < 0) {
1360 				SPDK_ERRLOG("Failed to del rpi(%lx) hash entry\n",
1361 					    fc_conn->conn_id);
1362 			}
1363 			free(rport);
1364 		}
1365 	} else {
1366 		SPDK_ERRLOG("RPI(%d) hash entry not found\n", fc_conn->rpi);
1367 	}
1368 }
1369 
1370 static struct spdk_nvmf_fc_request *
1371 nvmf_fc_poller_rpi_find_req(struct spdk_nvmf_fc_hwqp *hwqp, uint16_t rpi, uint16_t oxid)
1372 {
1373 	struct spdk_nvmf_fc_request *fc_req = NULL;
1374 	struct spdk_nvmf_fc_conn *fc_conn;
1375 	struct spdk_nvmf_fc_hwqp_rport *rport = NULL;
1376 
1377 	if (rte_hash_lookup_data(hwqp->rport_list_hash, (void *)&rpi, (void **)&rport) >= 0) {
1378 		TAILQ_FOREACH(fc_conn, &rport->conn_list, rport_link) {
1379 			TAILQ_FOREACH(fc_req, &fc_conn->in_use_reqs, conn_link) {
1380 				if (fc_req->oxid == oxid) {
1381 					return fc_req;
1382 				}
1383 			}
1384 		}
1385 	}
1386 	return NULL;
1387 }
1388 
1389 static void
1390 nvmf_fc_poller_api_add_connection(void *arg)
1391 {
1392 	enum spdk_nvmf_fc_poller_api_ret ret = SPDK_NVMF_FC_POLLER_API_SUCCESS;
1393 	struct spdk_nvmf_fc_poller_api_add_connection_args *conn_args =
1394 		(struct spdk_nvmf_fc_poller_api_add_connection_args *)arg;
1395 	struct spdk_nvmf_fc_conn *fc_conn = conn_args->fc_conn, *tmp;
1396 
1397 	SPDK_DEBUGLOG(nvmf_fc_poller_api, "Poller add connection, conn_id 0x%lx\n",
1398 		      fc_conn->conn_id);
1399 
1400 	/* make sure connection is not already in poller's list */
1401 	if (rte_hash_lookup_data(fc_conn->hwqp->connection_list_hash,
1402 				 (void *)&fc_conn->conn_id, (void **)&tmp) >= 0) {
1403 		SPDK_ERRLOG("duplicate connection found");
1404 		ret = SPDK_NVMF_FC_POLLER_API_DUP_CONN_ID;
1405 	} else {
1406 		if (nvmf_fc_poller_add_conn_lookup_data(fc_conn->hwqp, fc_conn)) {
1407 			SPDK_ERRLOG("Failed to add connection 0x%lx\n", fc_conn->conn_id);
1408 			ret = SPDK_NVMF_FC_POLLER_API_ERROR;
1409 		} else {
1410 			SPDK_DEBUGLOG(nvmf_fc_poller_api, "conn_id=%lx", fc_conn->conn_id);
1411 			fc_conn->hwqp->num_conns++;
1412 		}
1413 	}
1414 
1415 	/* perform callback */
1416 	nvmf_fc_poller_api_perform_cb(&conn_args->cb_info, ret);
1417 }
1418 
1419 static void
1420 nvmf_fc_poller_api_quiesce_queue(void *arg)
1421 {
1422 	struct spdk_nvmf_fc_poller_api_quiesce_queue_args *q_args =
1423 		(struct spdk_nvmf_fc_poller_api_quiesce_queue_args *) arg;
1424 	struct spdk_nvmf_fc_request *fc_req = NULL, *tmp;
1425 
1426 	/* should be already, but make sure queue is quiesced */
1427 	q_args->hwqp->state = SPDK_FC_HWQP_OFFLINE;
1428 
1429 	/*
1430 	 * Kill all the outstanding commands that are in the transfer state and
1431 	 * in the process of being aborted.
1432 	 * We can run into this situation if an adapter reset happens when an I_T Nexus delete
1433 	 * is in progress.
1434 	 */
1435 	TAILQ_FOREACH_SAFE(fc_req, &q_args->hwqp->in_use_reqs, link, tmp) {
1436 		if (nvmf_fc_req_in_xfer(fc_req) && fc_req->is_aborted == true) {
1437 			nvmf_fc_poller_api_func(q_args->hwqp, SPDK_NVMF_FC_POLLER_API_REQ_ABORT_COMPLETE,
1438 						(void *)fc_req);
1439 		}
1440 	}
1441 
1442 	/* perform callback */
1443 	nvmf_fc_poller_api_perform_cb(&q_args->cb_info, SPDK_NVMF_FC_POLLER_API_SUCCESS);
1444 }
1445 
1446 static void
1447 nvmf_fc_poller_api_activate_queue(void *arg)
1448 {
1449 	struct spdk_nvmf_fc_poller_api_quiesce_queue_args *q_args =
1450 		(struct spdk_nvmf_fc_poller_api_quiesce_queue_args *) arg;
1451 
1452 	q_args->hwqp->state = SPDK_FC_HWQP_ONLINE;
1453 
1454 	/* perform callback */
1455 	nvmf_fc_poller_api_perform_cb(&q_args->cb_info, 0);
1456 }
1457 
1458 static void
1459 nvmf_fc_disconnect_qpair_cb(void *ctx)
1460 {
1461 	struct spdk_nvmf_fc_poller_api_cb_info *cb_info = ctx;
1462 	/* perform callback */
1463 	nvmf_fc_poller_api_perform_cb(cb_info, SPDK_NVMF_FC_POLLER_API_SUCCESS);
1464 }
1465 
1466 static void
1467 nvmf_fc_poller_conn_abort_done(void *hwqp, int32_t status, void *cb_args)
1468 {
1469 	struct spdk_nvmf_fc_poller_api_del_connection_args *conn_args = cb_args;
1470 
1471 	if (conn_args->fc_request_cnt) {
1472 		conn_args->fc_request_cnt -= 1;
1473 	}
1474 
1475 	if (!conn_args->fc_request_cnt) {
1476 		struct spdk_nvmf_fc_conn *fc_conn = conn_args->fc_conn, *tmp;
1477 
1478 		if (rte_hash_lookup_data(conn_args->hwqp->connection_list_hash,
1479 					 (void *)&fc_conn->conn_id, (void *)&tmp) >= 0) {
1480 			/* All the requests for this connection are aborted. */
1481 			nvmf_fc_poller_del_conn_lookup_data(conn_args->hwqp, fc_conn);
1482 			fc_conn->hwqp->num_conns--;
1483 
1484 			SPDK_DEBUGLOG(nvmf_fc_poller_api, "Connection deleted, conn_id 0x%lx\n", fc_conn->conn_id);
1485 
1486 			if (!conn_args->backend_initiated && (fc_conn->qpair.state != SPDK_NVMF_QPAIR_DEACTIVATING)) {
1487 				/* disconnect qpair from nvmf controller */
1488 				fc_conn->qpair_disconnect_cb_fn = nvmf_fc_disconnect_qpair_cb;
1489 				fc_conn->qpair_disconnect_ctx = &conn_args->cb_info;
1490 				spdk_nvmf_qpair_disconnect(&fc_conn->qpair);
1491 			} else {
1492 				nvmf_fc_poller_api_perform_cb(&conn_args->cb_info, SPDK_NVMF_FC_POLLER_API_SUCCESS);
1493 			}
1494 		} else {
1495 			/*
1496 			 * Duplicate connection delete can happen if one is
1497 			 * coming in via an association disconnect and the other
1498 			 * is initiated by a port reset.
1499 			 */
1500 			SPDK_DEBUGLOG(nvmf_fc_poller_api, "Duplicate conn delete.");
1501 			/* perform callback */
1502 			nvmf_fc_poller_api_perform_cb(&conn_args->cb_info, SPDK_NVMF_FC_POLLER_API_SUCCESS);
1503 		}
1504 	}
1505 }
1506 
1507 static void
1508 nvmf_fc_poller_api_del_connection(void *arg)
1509 {
1510 	struct spdk_nvmf_fc_poller_api_del_connection_args *conn_args =
1511 		(struct spdk_nvmf_fc_poller_api_del_connection_args *)arg;
1512 	struct spdk_nvmf_fc_conn *fc_conn = NULL;
1513 	struct spdk_nvmf_fc_request *fc_req = NULL, *tmp;
1514 	struct spdk_nvmf_fc_hwqp *hwqp = conn_args->hwqp;
1515 
1516 	SPDK_DEBUGLOG(nvmf_fc_poller_api, "Poller delete connection, conn_id 0x%lx\n",
1517 		      fc_conn->conn_id);
1518 
1519 	/* Make sure connection is valid */
1520 	if (rte_hash_lookup_data(hwqp->connection_list_hash,
1521 				 (void *)&conn_args->fc_conn->conn_id, (void **)&fc_conn) < 0) {
1522 		/* perform callback */
1523 		nvmf_fc_poller_api_perform_cb(&conn_args->cb_info, SPDK_NVMF_FC_POLLER_API_NO_CONN_ID);
1524 		return;
1525 	}
1526 
1527 	conn_args->fc_request_cnt = 0;
1528 
1529 	TAILQ_FOREACH_SAFE(fc_req, &fc_conn->in_use_reqs, conn_link, tmp) {
1530 		if (nvmf_qpair_is_admin_queue(&fc_conn->qpair) &&
1531 		    (fc_req->req.cmd->nvme_cmd.opc == SPDK_NVME_OPC_ASYNC_EVENT_REQUEST)) {
1532 			/* AER will be cleaned by spdk_nvmf_qpair_disconnect. */
1533 			continue;
1534 		}
1535 
1536 		conn_args->fc_request_cnt += 1;
1537 		nvmf_fc_request_abort(fc_req, conn_args->send_abts,
1538 				      nvmf_fc_poller_conn_abort_done,
1539 				      conn_args);
1540 	}
1541 
1542 	if (!conn_args->fc_request_cnt) {
1543 		SPDK_DEBUGLOG(nvmf_fc_poller_api, "Connection deleted.\n");
1544 		nvmf_fc_poller_del_conn_lookup_data(conn_args->hwqp, conn_args->fc_conn);
1545 		hwqp->num_conns--;
1546 
1547 		if (!conn_args->backend_initiated && (fc_conn->qpair.state != SPDK_NVMF_QPAIR_DEACTIVATING)) {
1548 			/* disconnect qpair from nvmf controller */
1549 			fc_conn->qpair_disconnect_cb_fn = nvmf_fc_disconnect_qpair_cb;
1550 			fc_conn->qpair_disconnect_ctx = &conn_args->cb_info;
1551 			spdk_nvmf_qpair_disconnect(&fc_conn->qpair);
1552 		} else {
1553 			nvmf_fc_poller_api_perform_cb(&conn_args->cb_info, SPDK_NVMF_FC_POLLER_API_SUCCESS);
1554 		}
1555 	}
1556 }
1557 
1558 static void
1559 nvmf_fc_poller_abts_done(void *hwqp, int32_t status, void *cb_args)
1560 {
1561 	struct spdk_nvmf_fc_poller_api_abts_recvd_args *args = cb_args;
1562 
1563 	SPDK_DEBUGLOG(nvmf_fc_poller_api,
1564 		      "ABTS poller done, rpi: 0x%x, oxid: 0x%x, rxid: 0x%x\n",
1565 		      args->ctx->rpi, args->ctx->oxid, args->ctx->rxid);
1566 
1567 	nvmf_fc_poller_api_perform_cb(&args->cb_info,
1568 				      SPDK_NVMF_FC_POLLER_API_SUCCESS);
1569 }
1570 
1571 static void
1572 nvmf_fc_poller_api_abts_received(void *arg)
1573 {
1574 	struct spdk_nvmf_fc_poller_api_abts_recvd_args *args = arg;
1575 	struct spdk_nvmf_fc_request *fc_req;
1576 
1577 	fc_req = nvmf_fc_poller_rpi_find_req(args->hwqp, args->ctx->rpi, args->ctx->oxid);
1578 	if (fc_req) {
1579 		nvmf_fc_request_abort(fc_req, false, nvmf_fc_poller_abts_done, args);
1580 		return;
1581 	}
1582 
1583 	nvmf_fc_poller_api_perform_cb(&args->cb_info,
1584 				      SPDK_NVMF_FC_POLLER_API_OXID_NOT_FOUND);
1585 }
1586 
1587 static void
1588 nvmf_fc_poller_api_queue_sync(void *arg)
1589 {
1590 	struct spdk_nvmf_fc_poller_api_queue_sync_args *args = arg;
1591 
1592 	SPDK_DEBUGLOG(nvmf_fc_poller_api,
1593 		      "HWQP sync requested for u_id = 0x%lx\n", args->u_id);
1594 
1595 	/* Add this args to hwqp sync_cb list */
1596 	TAILQ_INSERT_TAIL(&args->hwqp->sync_cbs, args, link);
1597 }
1598 
1599 static void
1600 nvmf_fc_poller_api_queue_sync_done(void *arg)
1601 {
1602 	struct spdk_nvmf_fc_poller_api_queue_sync_done_args *args = arg;
1603 	struct spdk_nvmf_fc_hwqp *hwqp = args->hwqp;
1604 	uint64_t tag = args->tag;
1605 	struct spdk_nvmf_fc_poller_api_queue_sync_args *sync_args = NULL, *tmp = NULL;
1606 
1607 	assert(args != NULL);
1608 
1609 	TAILQ_FOREACH_SAFE(sync_args, &hwqp->sync_cbs, link, tmp) {
1610 		if (sync_args->u_id == tag) {
1611 			/* Queue successfully synced. Remove from cb list */
1612 			TAILQ_REMOVE(&hwqp->sync_cbs, sync_args, link);
1613 
1614 			SPDK_DEBUGLOG(nvmf_fc_poller_api,
1615 				      "HWQP sync done for u_id = 0x%lx\n", sync_args->u_id);
1616 
1617 			/* Return the status to poller */
1618 			nvmf_fc_poller_api_perform_cb(&sync_args->cb_info,
1619 						      SPDK_NVMF_FC_POLLER_API_SUCCESS);
1620 			return;
1621 		}
1622 	}
1623 
1624 	free(arg);
1625 	/* note: no callback from this api */
1626 }
1627 
1628 static void
1629 nvmf_fc_poller_api_add_hwqp(void *arg)
1630 {
1631 	struct spdk_nvmf_fc_hwqp *hwqp = (struct spdk_nvmf_fc_hwqp *)arg;
1632 	struct spdk_nvmf_fc_poll_group *fgroup = hwqp->fgroup;
1633 
1634 	assert(fgroup);
1635 
1636 	if (nvmf_fc_poll_group_valid(fgroup)) {
1637 		TAILQ_INSERT_TAIL(&fgroup->hwqp_list, hwqp, link);
1638 		hwqp->lcore_id	= spdk_env_get_current_core();
1639 	}
1640 	/* note: no callback from this api */
1641 }
1642 
1643 static void
1644 nvmf_fc_poller_api_remove_hwqp(void *arg)
1645 {
1646 	struct spdk_nvmf_fc_poller_api_remove_hwqp_args *args = arg;
1647 	struct spdk_nvmf_fc_hwqp *hwqp = args->hwqp;
1648 	struct spdk_nvmf_fc_poll_group *fgroup = hwqp->fgroup;
1649 
1650 	if (nvmf_fc_poll_group_valid(fgroup)) {
1651 		TAILQ_REMOVE(&fgroup->hwqp_list, hwqp, link);
1652 	}
1653 	hwqp->fgroup = NULL;
1654 	hwqp->thread = NULL;
1655 
1656 	nvmf_fc_poller_api_perform_cb(&args->cb_info, SPDK_NVMF_FC_POLLER_API_SUCCESS);
1657 }
1658 
1659 enum spdk_nvmf_fc_poller_api_ret
1660 nvmf_fc_poller_api_func(struct spdk_nvmf_fc_hwqp *hwqp, enum spdk_nvmf_fc_poller_api api,
1661 			void *api_args) {
1662 	switch (api)
1663 	{
1664 	case SPDK_NVMF_FC_POLLER_API_ADD_CONNECTION:
1665 				spdk_thread_send_msg(hwqp->thread,
1666 						     nvmf_fc_poller_api_add_connection, api_args);
1667 		break;
1668 
1669 	case SPDK_NVMF_FC_POLLER_API_DEL_CONNECTION:
1670 		spdk_thread_send_msg(hwqp->thread,
1671 				     nvmf_fc_poller_api_del_connection, api_args);
1672 		break;
1673 
1674 	case SPDK_NVMF_FC_POLLER_API_QUIESCE_QUEUE:
1675 		/* quiesce q polling now, don't wait for poller to do it */
1676 		hwqp->state = SPDK_FC_HWQP_OFFLINE;
1677 		spdk_thread_send_msg(hwqp->thread,
1678 				     nvmf_fc_poller_api_quiesce_queue, api_args);
1679 		break;
1680 
1681 	case SPDK_NVMF_FC_POLLER_API_ACTIVATE_QUEUE:
1682 		spdk_thread_send_msg(hwqp->thread,
1683 				     nvmf_fc_poller_api_activate_queue, api_args);
1684 		break;
1685 
1686 	case SPDK_NVMF_FC_POLLER_API_ABTS_RECEIVED:
1687 		spdk_thread_send_msg(hwqp->thread,
1688 				     nvmf_fc_poller_api_abts_received, api_args);
1689 		break;
1690 
1691 	case SPDK_NVMF_FC_POLLER_API_REQ_ABORT_COMPLETE:
1692 		spdk_thread_send_msg(hwqp->thread,
1693 				     nvmf_fc_request_abort_complete, api_args);
1694 		break;
1695 
1696 	case SPDK_NVMF_FC_POLLER_API_QUEUE_SYNC:
1697 		spdk_thread_send_msg(hwqp->thread,
1698 				     nvmf_fc_poller_api_queue_sync, api_args);
1699 		break;
1700 
1701 	case SPDK_NVMF_FC_POLLER_API_QUEUE_SYNC_DONE:
1702 		spdk_thread_send_msg(hwqp->thread,
1703 				     nvmf_fc_poller_api_queue_sync_done, api_args);
1704 		break;
1705 
1706 	case SPDK_NVMF_FC_POLLER_API_ADD_HWQP:
1707 		spdk_thread_send_msg(hwqp->thread, nvmf_fc_poller_api_add_hwqp, (void *) hwqp);
1708 		break;
1709 
1710 	case SPDK_NVMF_FC_POLLER_API_REMOVE_HWQP:
1711 		spdk_thread_send_msg(hwqp->thread, nvmf_fc_poller_api_remove_hwqp, api_args);
1712 		break;
1713 
1714 	case SPDK_NVMF_FC_POLLER_API_ADAPTER_EVENT:
1715 	case SPDK_NVMF_FC_POLLER_API_AEN:
1716 	default:
1717 		SPDK_ERRLOG("BAD ARG!");
1718 		return SPDK_NVMF_FC_POLLER_API_INVALID_ARG;
1719 	}
1720 
1721 	return SPDK_NVMF_FC_POLLER_API_SUCCESS;
1722 }
1723 
1724 SPDK_LOG_REGISTER_COMPONENT(nvmf_fc_poller_api)
1725 SPDK_LOG_REGISTER_COMPONENT(nvmf_fc_ls)
1726