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