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