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