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