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