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