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