1aa1207eaSJohn Baldwin /*- 2aa1207eaSJohn Baldwin * SPDX-License-Identifier: BSD-2-Clause 3aa1207eaSJohn Baldwin * 4aa1207eaSJohn Baldwin * Copyright (c) 2022-2024 Chelsio Communications, Inc. 5aa1207eaSJohn Baldwin * Written by: John Baldwin <jhb@FreeBSD.org> 6aa1207eaSJohn Baldwin */ 7aa1207eaSJohn Baldwin 8aa1207eaSJohn Baldwin #include <sys/param.h> 9aa1207eaSJohn Baldwin #include <sys/kernel.h> 10aa1207eaSJohn Baldwin #include <sys/limits.h> 11aa1207eaSJohn Baldwin #include <sys/lock.h> 12aa1207eaSJohn Baldwin #include <sys/malloc.h> 13aa1207eaSJohn Baldwin #include <sys/mbuf.h> 14aa1207eaSJohn Baldwin #include <sys/module.h> 15*365b89e8SJohn Baldwin #include <sys/nv.h> 16aa1207eaSJohn Baldwin #include <sys/refcount.h> 17aa1207eaSJohn Baldwin #include <sys/sysctl.h> 18aa1207eaSJohn Baldwin #include <sys/sx.h> 19aa1207eaSJohn Baldwin #include <dev/nvme/nvme.h> 20aa1207eaSJohn Baldwin #include <dev/nvmf/nvmf.h> 21aa1207eaSJohn Baldwin #include <dev/nvmf/nvmf_transport.h> 22aa1207eaSJohn Baldwin #include <dev/nvmf/nvmf_transport_internal.h> 23aa1207eaSJohn Baldwin 24aa1207eaSJohn Baldwin /* Transport-independent support for fabrics queue pairs and commands. */ 25aa1207eaSJohn Baldwin 26aa1207eaSJohn Baldwin struct nvmf_transport { 27aa1207eaSJohn Baldwin struct nvmf_transport_ops *nt_ops; 28aa1207eaSJohn Baldwin 29aa1207eaSJohn Baldwin volatile u_int nt_active_qpairs; 30aa1207eaSJohn Baldwin SLIST_ENTRY(nvmf_transport) nt_link; 31aa1207eaSJohn Baldwin }; 32aa1207eaSJohn Baldwin 33aa1207eaSJohn Baldwin /* nvmf_transports[nvmf_trtype] is sorted by priority */ 34aa1207eaSJohn Baldwin static SLIST_HEAD(, nvmf_transport) nvmf_transports[NVMF_TRTYPE_TCP + 1]; 35aa1207eaSJohn Baldwin static struct sx nvmf_transports_lock; 36aa1207eaSJohn Baldwin 37aa1207eaSJohn Baldwin static MALLOC_DEFINE(M_NVMF_TRANSPORT, "nvmf_xport", 38aa1207eaSJohn Baldwin "NVMe over Fabrics transport"); 39aa1207eaSJohn Baldwin 40aa1207eaSJohn Baldwin SYSCTL_NODE(_kern, OID_AUTO, nvmf, CTLFLAG_RD | CTLFLAG_MPSAFE, 0, 41aa1207eaSJohn Baldwin "NVMe over Fabrics"); 42aa1207eaSJohn Baldwin 43aa1207eaSJohn Baldwin static bool 44aa1207eaSJohn Baldwin nvmf_supported_trtype(enum nvmf_trtype trtype) 45aa1207eaSJohn Baldwin { 46aa1207eaSJohn Baldwin return (trtype < nitems(nvmf_transports)); 47aa1207eaSJohn Baldwin } 48aa1207eaSJohn Baldwin 49aa1207eaSJohn Baldwin struct nvmf_qpair * 50aa1207eaSJohn Baldwin nvmf_allocate_qpair(enum nvmf_trtype trtype, bool controller, 51*365b89e8SJohn Baldwin const nvlist_t *params, nvmf_qpair_error_t *error_cb, void *error_cb_arg, 52aa1207eaSJohn Baldwin nvmf_capsule_receive_t *receive_cb, void *receive_cb_arg) 53aa1207eaSJohn Baldwin { 54aa1207eaSJohn Baldwin struct nvmf_transport *nt; 55aa1207eaSJohn Baldwin struct nvmf_qpair *qp; 56aa1207eaSJohn Baldwin 57aa1207eaSJohn Baldwin if (!nvmf_supported_trtype(trtype)) 58aa1207eaSJohn Baldwin return (NULL); 59aa1207eaSJohn Baldwin 60aa1207eaSJohn Baldwin sx_slock(&nvmf_transports_lock); 61aa1207eaSJohn Baldwin SLIST_FOREACH(nt, &nvmf_transports[trtype], nt_link) { 62aa1207eaSJohn Baldwin qp = nt->nt_ops->allocate_qpair(controller, params); 63aa1207eaSJohn Baldwin if (qp != NULL) { 64aa1207eaSJohn Baldwin refcount_acquire(&nt->nt_active_qpairs); 65aa1207eaSJohn Baldwin break; 66aa1207eaSJohn Baldwin } 67aa1207eaSJohn Baldwin } 68aa1207eaSJohn Baldwin sx_sunlock(&nvmf_transports_lock); 69aa1207eaSJohn Baldwin if (qp == NULL) 70aa1207eaSJohn Baldwin return (NULL); 71aa1207eaSJohn Baldwin 72aa1207eaSJohn Baldwin qp->nq_transport = nt; 73aa1207eaSJohn Baldwin qp->nq_ops = nt->nt_ops; 74aa1207eaSJohn Baldwin qp->nq_controller = controller; 75aa1207eaSJohn Baldwin qp->nq_error = error_cb; 76aa1207eaSJohn Baldwin qp->nq_error_arg = error_cb_arg; 77aa1207eaSJohn Baldwin qp->nq_receive = receive_cb; 78aa1207eaSJohn Baldwin qp->nq_receive_arg = receive_cb_arg; 79*365b89e8SJohn Baldwin qp->nq_admin = nvlist_get_bool(params, "admin"); 80aa1207eaSJohn Baldwin return (qp); 81aa1207eaSJohn Baldwin } 82aa1207eaSJohn Baldwin 83aa1207eaSJohn Baldwin void 84aa1207eaSJohn Baldwin nvmf_free_qpair(struct nvmf_qpair *qp) 85aa1207eaSJohn Baldwin { 86aa1207eaSJohn Baldwin struct nvmf_transport *nt; 87aa1207eaSJohn Baldwin 88aa1207eaSJohn Baldwin nt = qp->nq_transport; 89aa1207eaSJohn Baldwin qp->nq_ops->free_qpair(qp); 90aa1207eaSJohn Baldwin if (refcount_release(&nt->nt_active_qpairs)) 91aa1207eaSJohn Baldwin wakeup(nt); 92aa1207eaSJohn Baldwin } 93aa1207eaSJohn Baldwin 94aa1207eaSJohn Baldwin struct nvmf_capsule * 95aa1207eaSJohn Baldwin nvmf_allocate_command(struct nvmf_qpair *qp, const void *sqe, int how) 96aa1207eaSJohn Baldwin { 97aa1207eaSJohn Baldwin struct nvmf_capsule *nc; 98aa1207eaSJohn Baldwin 99aa1207eaSJohn Baldwin KASSERT(how == M_WAITOK || how == M_NOWAIT, 100aa1207eaSJohn Baldwin ("%s: invalid how", __func__)); 101aa1207eaSJohn Baldwin nc = qp->nq_ops->allocate_capsule(qp, how); 102aa1207eaSJohn Baldwin if (nc == NULL) 103aa1207eaSJohn Baldwin return (NULL); 104aa1207eaSJohn Baldwin 105aa1207eaSJohn Baldwin nc->nc_qpair = qp; 106aa1207eaSJohn Baldwin nc->nc_qe_len = sizeof(struct nvme_command); 107aa1207eaSJohn Baldwin memcpy(&nc->nc_sqe, sqe, nc->nc_qe_len); 108aa1207eaSJohn Baldwin 109aa1207eaSJohn Baldwin /* 4.2 of NVMe base spec: Fabrics always uses SGL. */ 110aa1207eaSJohn Baldwin nc->nc_sqe.fuse &= ~NVMEM(NVME_CMD_PSDT); 111aa1207eaSJohn Baldwin nc->nc_sqe.fuse |= NVMEF(NVME_CMD_PSDT, NVME_PSDT_SGL); 112aa1207eaSJohn Baldwin return (nc); 113aa1207eaSJohn Baldwin } 114aa1207eaSJohn Baldwin 115aa1207eaSJohn Baldwin struct nvmf_capsule * 116aa1207eaSJohn Baldwin nvmf_allocate_response(struct nvmf_qpair *qp, const void *cqe, int how) 117aa1207eaSJohn Baldwin { 118aa1207eaSJohn Baldwin struct nvmf_capsule *nc; 119aa1207eaSJohn Baldwin 120aa1207eaSJohn Baldwin KASSERT(how == M_WAITOK || how == M_NOWAIT, 121aa1207eaSJohn Baldwin ("%s: invalid how", __func__)); 122aa1207eaSJohn Baldwin nc = qp->nq_ops->allocate_capsule(qp, how); 123aa1207eaSJohn Baldwin if (nc == NULL) 124aa1207eaSJohn Baldwin return (NULL); 125aa1207eaSJohn Baldwin 126aa1207eaSJohn Baldwin nc->nc_qpair = qp; 127aa1207eaSJohn Baldwin nc->nc_qe_len = sizeof(struct nvme_completion); 128aa1207eaSJohn Baldwin memcpy(&nc->nc_cqe, cqe, nc->nc_qe_len); 129aa1207eaSJohn Baldwin return (nc); 130aa1207eaSJohn Baldwin } 131aa1207eaSJohn Baldwin 132aa1207eaSJohn Baldwin int 133aa1207eaSJohn Baldwin nvmf_capsule_append_data(struct nvmf_capsule *nc, struct memdesc *mem, 134aa1207eaSJohn Baldwin size_t len, bool send, nvmf_io_complete_t *complete_cb, 135aa1207eaSJohn Baldwin void *cb_arg) 136aa1207eaSJohn Baldwin { 137aa1207eaSJohn Baldwin if (nc->nc_data.io_len != 0) 138aa1207eaSJohn Baldwin return (EBUSY); 139aa1207eaSJohn Baldwin 140aa1207eaSJohn Baldwin nc->nc_send_data = send; 141aa1207eaSJohn Baldwin nc->nc_data.io_mem = *mem; 142aa1207eaSJohn Baldwin nc->nc_data.io_len = len; 143aa1207eaSJohn Baldwin nc->nc_data.io_complete = complete_cb; 144aa1207eaSJohn Baldwin nc->nc_data.io_complete_arg = cb_arg; 145aa1207eaSJohn Baldwin return (0); 146aa1207eaSJohn Baldwin } 147aa1207eaSJohn Baldwin 148aa1207eaSJohn Baldwin void 149aa1207eaSJohn Baldwin nvmf_free_capsule(struct nvmf_capsule *nc) 150aa1207eaSJohn Baldwin { 151aa1207eaSJohn Baldwin nc->nc_qpair->nq_ops->free_capsule(nc); 152aa1207eaSJohn Baldwin } 153aa1207eaSJohn Baldwin 154aa1207eaSJohn Baldwin int 155aa1207eaSJohn Baldwin nvmf_transmit_capsule(struct nvmf_capsule *nc) 156aa1207eaSJohn Baldwin { 157aa1207eaSJohn Baldwin return (nc->nc_qpair->nq_ops->transmit_capsule(nc)); 158aa1207eaSJohn Baldwin } 159aa1207eaSJohn Baldwin 160aa1207eaSJohn Baldwin void 161aa1207eaSJohn Baldwin nvmf_abort_capsule_data(struct nvmf_capsule *nc, int error) 162aa1207eaSJohn Baldwin { 163aa1207eaSJohn Baldwin if (nc->nc_data.io_len != 0) 164aa1207eaSJohn Baldwin nvmf_complete_io_request(&nc->nc_data, 0, error); 165aa1207eaSJohn Baldwin } 166aa1207eaSJohn Baldwin 167aa1207eaSJohn Baldwin void * 168aa1207eaSJohn Baldwin nvmf_capsule_sqe(struct nvmf_capsule *nc) 169aa1207eaSJohn Baldwin { 170aa1207eaSJohn Baldwin KASSERT(nc->nc_qe_len == sizeof(struct nvme_command), 171aa1207eaSJohn Baldwin ("%s: capsule %p is not a command capsule", __func__, nc)); 172aa1207eaSJohn Baldwin return (&nc->nc_sqe); 173aa1207eaSJohn Baldwin } 174aa1207eaSJohn Baldwin 175aa1207eaSJohn Baldwin void * 176aa1207eaSJohn Baldwin nvmf_capsule_cqe(struct nvmf_capsule *nc) 177aa1207eaSJohn Baldwin { 178aa1207eaSJohn Baldwin KASSERT(nc->nc_qe_len == sizeof(struct nvme_completion), 179aa1207eaSJohn Baldwin ("%s: capsule %p is not a response capsule", __func__, nc)); 180aa1207eaSJohn Baldwin return (&nc->nc_cqe); 181aa1207eaSJohn Baldwin } 182aa1207eaSJohn Baldwin 1834d3b659fSJohn Baldwin bool 1844d3b659fSJohn Baldwin nvmf_sqhd_valid(struct nvmf_capsule *nc) 1854d3b659fSJohn Baldwin { 1864d3b659fSJohn Baldwin KASSERT(nc->nc_qe_len == sizeof(struct nvme_completion), 1874d3b659fSJohn Baldwin ("%s: capsule %p is not a response capsule", __func__, nc)); 1884d3b659fSJohn Baldwin return (nc->nc_sqhd_valid); 1894d3b659fSJohn Baldwin } 1904d3b659fSJohn Baldwin 191aa1207eaSJohn Baldwin uint8_t 192aa1207eaSJohn Baldwin nvmf_validate_command_capsule(struct nvmf_capsule *nc) 193aa1207eaSJohn Baldwin { 194aa1207eaSJohn Baldwin KASSERT(nc->nc_qe_len == sizeof(struct nvme_command), 195aa1207eaSJohn Baldwin ("%s: capsule %p is not a command capsule", __func__, nc)); 196aa1207eaSJohn Baldwin 197aa1207eaSJohn Baldwin if (NVMEV(NVME_CMD_PSDT, nc->nc_sqe.fuse) != NVME_PSDT_SGL) 198aa1207eaSJohn Baldwin return (NVME_SC_INVALID_FIELD); 199aa1207eaSJohn Baldwin 200aa1207eaSJohn Baldwin return (nc->nc_qpair->nq_ops->validate_command_capsule(nc)); 201aa1207eaSJohn Baldwin } 202aa1207eaSJohn Baldwin 203aa1207eaSJohn Baldwin size_t 204aa1207eaSJohn Baldwin nvmf_capsule_data_len(const struct nvmf_capsule *nc) 205aa1207eaSJohn Baldwin { 206aa1207eaSJohn Baldwin return (nc->nc_qpair->nq_ops->capsule_data_len(nc)); 207aa1207eaSJohn Baldwin } 208aa1207eaSJohn Baldwin 209aa1207eaSJohn Baldwin int 210aa1207eaSJohn Baldwin nvmf_receive_controller_data(struct nvmf_capsule *nc, uint32_t data_offset, 211aa1207eaSJohn Baldwin struct memdesc *mem, size_t len, nvmf_io_complete_t *complete_cb, 212aa1207eaSJohn Baldwin void *cb_arg) 213aa1207eaSJohn Baldwin { 214aa1207eaSJohn Baldwin struct nvmf_io_request io; 215aa1207eaSJohn Baldwin 216aa1207eaSJohn Baldwin io.io_mem = *mem; 217aa1207eaSJohn Baldwin io.io_len = len; 218aa1207eaSJohn Baldwin io.io_complete = complete_cb; 219aa1207eaSJohn Baldwin io.io_complete_arg = cb_arg; 220aa1207eaSJohn Baldwin return (nc->nc_qpair->nq_ops->receive_controller_data(nc, data_offset, 221aa1207eaSJohn Baldwin &io)); 222aa1207eaSJohn Baldwin } 223aa1207eaSJohn Baldwin 224aa1207eaSJohn Baldwin u_int 225aa1207eaSJohn Baldwin nvmf_send_controller_data(struct nvmf_capsule *nc, uint32_t data_offset, 226aa1207eaSJohn Baldwin struct mbuf *m, size_t len) 227aa1207eaSJohn Baldwin { 228aa1207eaSJohn Baldwin MPASS(m_length(m, NULL) == len); 229aa1207eaSJohn Baldwin return (nc->nc_qpair->nq_ops->send_controller_data(nc, data_offset, m, 230aa1207eaSJohn Baldwin len)); 231aa1207eaSJohn Baldwin } 232aa1207eaSJohn Baldwin 233aa1207eaSJohn Baldwin int 234*365b89e8SJohn Baldwin nvmf_pack_ioc_nvlist(const nvlist_t *nvl, struct nvmf_ioc_nv *nv) 235*365b89e8SJohn Baldwin { 236*365b89e8SJohn Baldwin void *packed; 237*365b89e8SJohn Baldwin int error; 238*365b89e8SJohn Baldwin 239*365b89e8SJohn Baldwin error = nvlist_error(nvl); 240*365b89e8SJohn Baldwin if (error != 0) 241*365b89e8SJohn Baldwin return (error); 242*365b89e8SJohn Baldwin 243*365b89e8SJohn Baldwin if (nv->size == 0) { 244*365b89e8SJohn Baldwin nv->len = nvlist_size(nvl); 245*365b89e8SJohn Baldwin } else { 246*365b89e8SJohn Baldwin packed = nvlist_pack(nvl, &nv->len); 247*365b89e8SJohn Baldwin if (packed == NULL) 248*365b89e8SJohn Baldwin error = ENOMEM; 249*365b89e8SJohn Baldwin else if (nv->len > nv->size) 250*365b89e8SJohn Baldwin error = EFBIG; 251*365b89e8SJohn Baldwin else 252*365b89e8SJohn Baldwin error = copyout(packed, nv->data, nv->len); 253*365b89e8SJohn Baldwin free(packed, M_NVLIST); 254*365b89e8SJohn Baldwin } 255*365b89e8SJohn Baldwin return (error); 256*365b89e8SJohn Baldwin } 257*365b89e8SJohn Baldwin 258*365b89e8SJohn Baldwin int 259*365b89e8SJohn Baldwin nvmf_unpack_ioc_nvlist(const struct nvmf_ioc_nv *nv, nvlist_t **nvlp) 260*365b89e8SJohn Baldwin { 261*365b89e8SJohn Baldwin void *packed; 262*365b89e8SJohn Baldwin nvlist_t *nvl; 263*365b89e8SJohn Baldwin int error; 264*365b89e8SJohn Baldwin 265*365b89e8SJohn Baldwin packed = malloc(nv->size, M_NVMF_TRANSPORT, M_WAITOK); 266*365b89e8SJohn Baldwin error = copyin(nv->data, packed, nv->size); 267*365b89e8SJohn Baldwin if (error != 0) { 268*365b89e8SJohn Baldwin free(packed, M_NVMF_TRANSPORT); 269*365b89e8SJohn Baldwin return (error); 270*365b89e8SJohn Baldwin } 271*365b89e8SJohn Baldwin 272*365b89e8SJohn Baldwin nvl = nvlist_unpack(packed, nv->size, 0); 273*365b89e8SJohn Baldwin free(packed, M_NVMF_TRANSPORT); 274*365b89e8SJohn Baldwin if (nvl == NULL) 275*365b89e8SJohn Baldwin return (EINVAL); 276*365b89e8SJohn Baldwin 277*365b89e8SJohn Baldwin *nvlp = nvl; 278*365b89e8SJohn Baldwin return (0); 279*365b89e8SJohn Baldwin } 280*365b89e8SJohn Baldwin 281*365b89e8SJohn Baldwin bool 282*365b89e8SJohn Baldwin nvmf_validate_qpair_nvlist(const nvlist_t *nvl, bool controller) 283*365b89e8SJohn Baldwin { 284*365b89e8SJohn Baldwin uint64_t value, qsize; 285*365b89e8SJohn Baldwin bool admin, valid; 286*365b89e8SJohn Baldwin 287*365b89e8SJohn Baldwin valid = true; 288*365b89e8SJohn Baldwin valid &= nvlist_exists_bool(nvl, "admin"); 289*365b89e8SJohn Baldwin valid &= nvlist_exists_bool(nvl, "sq_flow_control"); 290*365b89e8SJohn Baldwin valid &= nvlist_exists_number(nvl, "qsize"); 291*365b89e8SJohn Baldwin valid &= nvlist_exists_number(nvl, "sqhd"); 292*365b89e8SJohn Baldwin if (!controller) 293*365b89e8SJohn Baldwin valid &= nvlist_exists_number(nvl, "sqtail"); 294*365b89e8SJohn Baldwin if (!valid) 295*365b89e8SJohn Baldwin return (false); 296*365b89e8SJohn Baldwin 297*365b89e8SJohn Baldwin admin = nvlist_get_bool(nvl, "admin"); 298*365b89e8SJohn Baldwin qsize = nvlist_get_number(nvl, "qsize"); 299*365b89e8SJohn Baldwin if (admin) { 300*365b89e8SJohn Baldwin if (qsize < NVME_MIN_ADMIN_ENTRIES || 301*365b89e8SJohn Baldwin qsize > NVME_MAX_ADMIN_ENTRIES) 302*365b89e8SJohn Baldwin return (false); 303*365b89e8SJohn Baldwin } else { 304*365b89e8SJohn Baldwin if (qsize < NVME_MIN_IO_ENTRIES || qsize > NVME_MAX_IO_ENTRIES) 305*365b89e8SJohn Baldwin return (false); 306*365b89e8SJohn Baldwin } 307*365b89e8SJohn Baldwin value = nvlist_get_number(nvl, "sqhd"); 308*365b89e8SJohn Baldwin if (value > qsize - 1) 309*365b89e8SJohn Baldwin return (false); 310*365b89e8SJohn Baldwin if (!controller) { 311*365b89e8SJohn Baldwin value = nvlist_get_number(nvl, "sqtail"); 312*365b89e8SJohn Baldwin if (value > qsize - 1) 313*365b89e8SJohn Baldwin return (false); 314*365b89e8SJohn Baldwin } 315*365b89e8SJohn Baldwin 316*365b89e8SJohn Baldwin return (true); 317*365b89e8SJohn Baldwin } 318*365b89e8SJohn Baldwin 319*365b89e8SJohn Baldwin int 320aa1207eaSJohn Baldwin nvmf_transport_module_handler(struct module *mod, int what, void *arg) 321aa1207eaSJohn Baldwin { 322aa1207eaSJohn Baldwin struct nvmf_transport_ops *ops = arg; 323aa1207eaSJohn Baldwin struct nvmf_transport *nt, *nt2, *prev; 324aa1207eaSJohn Baldwin int error; 325aa1207eaSJohn Baldwin 326aa1207eaSJohn Baldwin switch (what) { 327aa1207eaSJohn Baldwin case MOD_LOAD: 328aa1207eaSJohn Baldwin if (!nvmf_supported_trtype(ops->trtype)) { 329aa1207eaSJohn Baldwin printf("NVMF: Unsupported transport %u", ops->trtype); 330aa1207eaSJohn Baldwin return (EINVAL); 331aa1207eaSJohn Baldwin } 332aa1207eaSJohn Baldwin 333aa1207eaSJohn Baldwin nt = malloc(sizeof(*nt), M_NVMF_TRANSPORT, M_WAITOK | M_ZERO); 334aa1207eaSJohn Baldwin nt->nt_ops = arg; 335aa1207eaSJohn Baldwin 336aa1207eaSJohn Baldwin sx_xlock(&nvmf_transports_lock); 337aa1207eaSJohn Baldwin if (SLIST_EMPTY(&nvmf_transports[ops->trtype])) { 338aa1207eaSJohn Baldwin SLIST_INSERT_HEAD(&nvmf_transports[ops->trtype], nt, 339aa1207eaSJohn Baldwin nt_link); 340aa1207eaSJohn Baldwin } else { 341aa1207eaSJohn Baldwin prev = NULL; 342aa1207eaSJohn Baldwin SLIST_FOREACH(nt2, &nvmf_transports[ops->trtype], 343aa1207eaSJohn Baldwin nt_link) { 344aa1207eaSJohn Baldwin if (ops->priority > nt2->nt_ops->priority) 345aa1207eaSJohn Baldwin break; 346aa1207eaSJohn Baldwin prev = nt2; 347aa1207eaSJohn Baldwin } 348aa1207eaSJohn Baldwin if (prev == NULL) 349aa1207eaSJohn Baldwin SLIST_INSERT_HEAD(&nvmf_transports[ops->trtype], 350aa1207eaSJohn Baldwin nt, nt_link); 351aa1207eaSJohn Baldwin else 352aa1207eaSJohn Baldwin SLIST_INSERT_AFTER(prev, nt, nt_link); 353aa1207eaSJohn Baldwin } 354aa1207eaSJohn Baldwin sx_xunlock(&nvmf_transports_lock); 355aa1207eaSJohn Baldwin return (0); 356aa1207eaSJohn Baldwin 357aa1207eaSJohn Baldwin case MOD_QUIESCE: 358aa1207eaSJohn Baldwin if (!nvmf_supported_trtype(ops->trtype)) 359aa1207eaSJohn Baldwin return (0); 360aa1207eaSJohn Baldwin 361aa1207eaSJohn Baldwin sx_slock(&nvmf_transports_lock); 362aa1207eaSJohn Baldwin SLIST_FOREACH(nt, &nvmf_transports[ops->trtype], nt_link) { 363aa1207eaSJohn Baldwin if (nt->nt_ops == ops) 364aa1207eaSJohn Baldwin break; 365aa1207eaSJohn Baldwin } 366aa1207eaSJohn Baldwin if (nt == NULL) { 367aa1207eaSJohn Baldwin sx_sunlock(&nvmf_transports_lock); 368aa1207eaSJohn Baldwin return (0); 369aa1207eaSJohn Baldwin } 370aa1207eaSJohn Baldwin if (nt->nt_active_qpairs != 0) { 371aa1207eaSJohn Baldwin sx_sunlock(&nvmf_transports_lock); 372aa1207eaSJohn Baldwin return (EBUSY); 373aa1207eaSJohn Baldwin } 374aa1207eaSJohn Baldwin sx_sunlock(&nvmf_transports_lock); 375aa1207eaSJohn Baldwin return (0); 376aa1207eaSJohn Baldwin 377aa1207eaSJohn Baldwin case MOD_UNLOAD: 378aa1207eaSJohn Baldwin if (!nvmf_supported_trtype(ops->trtype)) 379aa1207eaSJohn Baldwin return (0); 380aa1207eaSJohn Baldwin 381aa1207eaSJohn Baldwin sx_xlock(&nvmf_transports_lock); 382aa1207eaSJohn Baldwin prev = NULL; 383aa1207eaSJohn Baldwin SLIST_FOREACH(nt, &nvmf_transports[ops->trtype], nt_link) { 384aa1207eaSJohn Baldwin if (nt->nt_ops == ops) 385aa1207eaSJohn Baldwin break; 386aa1207eaSJohn Baldwin prev = nt; 387aa1207eaSJohn Baldwin } 388aa1207eaSJohn Baldwin if (nt == NULL) { 389aa1207eaSJohn Baldwin sx_xunlock(&nvmf_transports_lock); 390aa1207eaSJohn Baldwin return (0); 391aa1207eaSJohn Baldwin } 392aa1207eaSJohn Baldwin 393aa1207eaSJohn Baldwin if (prev == NULL) 394aa1207eaSJohn Baldwin SLIST_REMOVE_HEAD(&nvmf_transports[ops->trtype], 395aa1207eaSJohn Baldwin nt_link); 396aa1207eaSJohn Baldwin else 397aa1207eaSJohn Baldwin SLIST_REMOVE_AFTER(prev, nt_link); 398aa1207eaSJohn Baldwin 399aa1207eaSJohn Baldwin error = 0; 400aa1207eaSJohn Baldwin while (nt->nt_active_qpairs != 0 && error == 0) 401aa1207eaSJohn Baldwin error = sx_sleep(nt, &nvmf_transports_lock, PCATCH, 402aa1207eaSJohn Baldwin "nftunld", 0); 403aa1207eaSJohn Baldwin sx_xunlock(&nvmf_transports_lock); 404aa1207eaSJohn Baldwin if (error != 0) 405aa1207eaSJohn Baldwin return (error); 406aa1207eaSJohn Baldwin free(nt, M_NVMF_TRANSPORT); 407aa1207eaSJohn Baldwin return (0); 408aa1207eaSJohn Baldwin 409aa1207eaSJohn Baldwin default: 410aa1207eaSJohn Baldwin return (EOPNOTSUPP); 411aa1207eaSJohn Baldwin } 412aa1207eaSJohn Baldwin } 413aa1207eaSJohn Baldwin 414aa1207eaSJohn Baldwin static int 415aa1207eaSJohn Baldwin nvmf_transport_modevent(module_t mod __unused, int what, void *arg __unused) 416aa1207eaSJohn Baldwin { 417aa1207eaSJohn Baldwin switch (what) { 418aa1207eaSJohn Baldwin case MOD_LOAD: 419aa1207eaSJohn Baldwin for (u_int i = 0; i < nitems(nvmf_transports); i++) 420aa1207eaSJohn Baldwin SLIST_INIT(&nvmf_transports[i]); 421aa1207eaSJohn Baldwin sx_init(&nvmf_transports_lock, "nvmf transports"); 422aa1207eaSJohn Baldwin return (0); 423aa1207eaSJohn Baldwin default: 424aa1207eaSJohn Baldwin return (EOPNOTSUPP); 425aa1207eaSJohn Baldwin } 426aa1207eaSJohn Baldwin } 427aa1207eaSJohn Baldwin 428aa1207eaSJohn Baldwin static moduledata_t nvmf_transport_mod = { 429aa1207eaSJohn Baldwin "nvmf_transport", 430aa1207eaSJohn Baldwin nvmf_transport_modevent, 431aa1207eaSJohn Baldwin 0 432aa1207eaSJohn Baldwin }; 433aa1207eaSJohn Baldwin 434aa1207eaSJohn Baldwin DECLARE_MODULE(nvmf_transport, nvmf_transport_mod, SI_SUB_DRIVERS, 435aa1207eaSJohn Baldwin SI_ORDER_FIRST); 436aa1207eaSJohn Baldwin MODULE_VERSION(nvmf_transport, 1); 437