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