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