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