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