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