1a1eda741SJohn Baldwin /*- 2a1eda741SJohn Baldwin * SPDX-License-Identifier: BSD-2-Clause 3a1eda741SJohn Baldwin * 4a1eda741SJohn Baldwin * Copyright (c) 2023-2024 Chelsio Communications, Inc. 5a1eda741SJohn Baldwin * Written by: John Baldwin <jhb@FreeBSD.org> 6a1eda741SJohn Baldwin */ 7a1eda741SJohn Baldwin 8a1eda741SJohn Baldwin #include <sys/param.h> 9a1eda741SJohn Baldwin #include <sys/bus.h> 10a1eda741SJohn Baldwin #include <sys/conf.h> 11365b89e8SJohn Baldwin #include <sys/dnv.h> 12f46d4971SJohn Baldwin #include <sys/eventhandler.h> 13a1eda741SJohn Baldwin #include <sys/lock.h> 14a1eda741SJohn Baldwin #include <sys/kernel.h> 15a1eda741SJohn Baldwin #include <sys/malloc.h> 16a1eda741SJohn Baldwin #include <sys/memdesc.h> 17a1eda741SJohn Baldwin #include <sys/module.h> 18a1eda741SJohn Baldwin #include <sys/mutex.h> 19365b89e8SJohn Baldwin #include <sys/nv.h> 20f46d4971SJohn Baldwin #include <sys/reboot.h> 21a1eda741SJohn Baldwin #include <sys/sx.h> 22aacaeeeeSJohn Baldwin #include <sys/sysctl.h> 23a1eda741SJohn Baldwin #include <sys/taskqueue.h> 24a1eda741SJohn Baldwin #include <dev/nvme/nvme.h> 25a1eda741SJohn Baldwin #include <dev/nvmf/nvmf.h> 26a1eda741SJohn Baldwin #include <dev/nvmf/nvmf_transport.h> 27a1eda741SJohn Baldwin #include <dev/nvmf/host/nvmf_var.h> 28a1eda741SJohn Baldwin 29a1eda741SJohn Baldwin static struct cdevsw nvmf_cdevsw; 30a1eda741SJohn Baldwin 31aacaeeeeSJohn Baldwin bool nvmf_fail_disconnect = false; 32aacaeeeeSJohn Baldwin SYSCTL_BOOL(_kern_nvmf, OID_AUTO, fail_on_disconnection, CTLFLAG_RWTUN, 33aacaeeeeSJohn Baldwin &nvmf_fail_disconnect, 0, "Fail I/O requests on connection failure"); 34aacaeeeeSJohn Baldwin 35a1eda741SJohn Baldwin MALLOC_DEFINE(M_NVMF, "nvmf", "NVMe over Fabrics host"); 36a1eda741SJohn Baldwin 37a1eda741SJohn Baldwin static void nvmf_disconnect_task(void *arg, int pending); 38f46d4971SJohn Baldwin static void nvmf_shutdown_pre_sync(void *arg, int howto); 39f46d4971SJohn Baldwin static void nvmf_shutdown_post_sync(void *arg, int howto); 40a1eda741SJohn Baldwin 41a1eda741SJohn Baldwin void 42a1eda741SJohn Baldwin nvmf_complete(void *arg, const struct nvme_completion *cqe) 43a1eda741SJohn Baldwin { 44a1eda741SJohn Baldwin struct nvmf_completion_status *status = arg; 45a1eda741SJohn Baldwin struct mtx *mtx; 46a1eda741SJohn Baldwin 47a1eda741SJohn Baldwin status->cqe = *cqe; 48a1eda741SJohn Baldwin mtx = mtx_pool_find(mtxpool_sleep, status); 49a1eda741SJohn Baldwin mtx_lock(mtx); 50a1eda741SJohn Baldwin status->done = true; 51a1eda741SJohn Baldwin mtx_unlock(mtx); 52a1eda741SJohn Baldwin wakeup(status); 53a1eda741SJohn Baldwin } 54a1eda741SJohn Baldwin 55a1eda741SJohn Baldwin void 56a1eda741SJohn Baldwin nvmf_io_complete(void *arg, size_t xfered, int error) 57a1eda741SJohn Baldwin { 58a1eda741SJohn Baldwin struct nvmf_completion_status *status = arg; 59a1eda741SJohn Baldwin struct mtx *mtx; 60a1eda741SJohn Baldwin 61a1eda741SJohn Baldwin status->io_error = error; 62a1eda741SJohn Baldwin mtx = mtx_pool_find(mtxpool_sleep, status); 63a1eda741SJohn Baldwin mtx_lock(mtx); 64a1eda741SJohn Baldwin status->io_done = true; 65a1eda741SJohn Baldwin mtx_unlock(mtx); 66a1eda741SJohn Baldwin wakeup(status); 67a1eda741SJohn Baldwin } 68a1eda741SJohn Baldwin 69a1eda741SJohn Baldwin void 70a1eda741SJohn Baldwin nvmf_wait_for_reply(struct nvmf_completion_status *status) 71a1eda741SJohn Baldwin { 72a1eda741SJohn Baldwin struct mtx *mtx; 73a1eda741SJohn Baldwin 74a1eda741SJohn Baldwin mtx = mtx_pool_find(mtxpool_sleep, status); 75a1eda741SJohn Baldwin mtx_lock(mtx); 76a1eda741SJohn Baldwin while (!status->done || !status->io_done) 77a1eda741SJohn Baldwin mtx_sleep(status, mtx, 0, "nvmfcmd", 0); 78a1eda741SJohn Baldwin mtx_unlock(mtx); 79a1eda741SJohn Baldwin } 80a1eda741SJohn Baldwin 81a1eda741SJohn Baldwin static int 82a1eda741SJohn Baldwin nvmf_read_property(struct nvmf_softc *sc, uint32_t offset, uint8_t size, 83a1eda741SJohn Baldwin uint64_t *value) 84a1eda741SJohn Baldwin { 85a1eda741SJohn Baldwin const struct nvmf_fabric_prop_get_rsp *rsp; 86a1eda741SJohn Baldwin struct nvmf_completion_status status; 87a1eda741SJohn Baldwin 88a1eda741SJohn Baldwin nvmf_status_init(&status); 89a1eda741SJohn Baldwin if (!nvmf_cmd_get_property(sc, offset, size, nvmf_complete, &status, 90a1eda741SJohn Baldwin M_WAITOK)) 91a1eda741SJohn Baldwin return (ECONNABORTED); 92a1eda741SJohn Baldwin nvmf_wait_for_reply(&status); 93a1eda741SJohn Baldwin 94a1eda741SJohn Baldwin if (status.cqe.status != 0) { 95a1eda741SJohn Baldwin device_printf(sc->dev, "PROPERTY_GET failed, status %#x\n", 96a1eda741SJohn Baldwin le16toh(status.cqe.status)); 97a1eda741SJohn Baldwin return (EIO); 98a1eda741SJohn Baldwin } 99a1eda741SJohn Baldwin 100a1eda741SJohn Baldwin rsp = (const struct nvmf_fabric_prop_get_rsp *)&status.cqe; 101a1eda741SJohn Baldwin if (size == 8) 102a1eda741SJohn Baldwin *value = le64toh(rsp->value.u64); 103a1eda741SJohn Baldwin else 104a1eda741SJohn Baldwin *value = le32toh(rsp->value.u32.low); 105a1eda741SJohn Baldwin return (0); 106a1eda741SJohn Baldwin } 107a1eda741SJohn Baldwin 108a1eda741SJohn Baldwin static int 109a1eda741SJohn Baldwin nvmf_write_property(struct nvmf_softc *sc, uint32_t offset, uint8_t size, 110a1eda741SJohn Baldwin uint64_t value) 111a1eda741SJohn Baldwin { 112a1eda741SJohn Baldwin struct nvmf_completion_status status; 113a1eda741SJohn Baldwin 114a1eda741SJohn Baldwin nvmf_status_init(&status); 115a1eda741SJohn Baldwin if (!nvmf_cmd_set_property(sc, offset, size, value, nvmf_complete, &status, 116a1eda741SJohn Baldwin M_WAITOK)) 117a1eda741SJohn Baldwin return (ECONNABORTED); 118a1eda741SJohn Baldwin nvmf_wait_for_reply(&status); 119a1eda741SJohn Baldwin 120a1eda741SJohn Baldwin if (status.cqe.status != 0) { 121a1eda741SJohn Baldwin device_printf(sc->dev, "PROPERTY_SET failed, status %#x\n", 122a1eda741SJohn Baldwin le16toh(status.cqe.status)); 123a1eda741SJohn Baldwin return (EIO); 124a1eda741SJohn Baldwin } 125a1eda741SJohn Baldwin return (0); 126a1eda741SJohn Baldwin } 127a1eda741SJohn Baldwin 128a1eda741SJohn Baldwin static void 129a1eda741SJohn Baldwin nvmf_shutdown_controller(struct nvmf_softc *sc) 130a1eda741SJohn Baldwin { 131a1eda741SJohn Baldwin uint64_t cc; 132a1eda741SJohn Baldwin int error; 133a1eda741SJohn Baldwin 134a1eda741SJohn Baldwin error = nvmf_read_property(sc, NVMF_PROP_CC, 4, &cc); 135a1eda741SJohn Baldwin if (error != 0) { 136a1eda741SJohn Baldwin device_printf(sc->dev, "Failed to fetch CC for shutdown\n"); 137a1eda741SJohn Baldwin return; 138a1eda741SJohn Baldwin } 139a1eda741SJohn Baldwin 140a1eda741SJohn Baldwin cc |= NVMEF(NVME_CC_REG_SHN, NVME_SHN_NORMAL); 141a1eda741SJohn Baldwin 142a1eda741SJohn Baldwin error = nvmf_write_property(sc, NVMF_PROP_CC, 4, cc); 143a1eda741SJohn Baldwin if (error != 0) 144a1eda741SJohn Baldwin device_printf(sc->dev, 145a1eda741SJohn Baldwin "Failed to set CC to trigger shutdown\n"); 146a1eda741SJohn Baldwin } 147a1eda741SJohn Baldwin 148a1eda741SJohn Baldwin static void 149a1eda741SJohn Baldwin nvmf_check_keep_alive(void *arg) 150a1eda741SJohn Baldwin { 151a1eda741SJohn Baldwin struct nvmf_softc *sc = arg; 152a1eda741SJohn Baldwin int traffic; 153a1eda741SJohn Baldwin 154a1eda741SJohn Baldwin traffic = atomic_readandclear_int(&sc->ka_active_rx_traffic); 155a1eda741SJohn Baldwin if (traffic == 0) { 156a1eda741SJohn Baldwin device_printf(sc->dev, 157a1eda741SJohn Baldwin "disconnecting due to KeepAlive timeout\n"); 158a1eda741SJohn Baldwin nvmf_disconnect(sc); 159a1eda741SJohn Baldwin return; 160a1eda741SJohn Baldwin } 161a1eda741SJohn Baldwin 162a1eda741SJohn Baldwin callout_schedule_sbt(&sc->ka_rx_timer, sc->ka_rx_sbt, 0, C_HARDCLOCK); 163a1eda741SJohn Baldwin } 164a1eda741SJohn Baldwin 165a1eda741SJohn Baldwin static void 166a1eda741SJohn Baldwin nvmf_keep_alive_complete(void *arg, const struct nvme_completion *cqe) 167a1eda741SJohn Baldwin { 168a1eda741SJohn Baldwin struct nvmf_softc *sc = arg; 169a1eda741SJohn Baldwin 170a1eda741SJohn Baldwin atomic_store_int(&sc->ka_active_rx_traffic, 1); 171a1eda741SJohn Baldwin if (cqe->status != 0) { 172a1eda741SJohn Baldwin device_printf(sc->dev, 173a1eda741SJohn Baldwin "KeepAlive response reported status %#x\n", 174a1eda741SJohn Baldwin le16toh(cqe->status)); 175a1eda741SJohn Baldwin } 176a1eda741SJohn Baldwin } 177a1eda741SJohn Baldwin 178a1eda741SJohn Baldwin static void 179a1eda741SJohn Baldwin nvmf_send_keep_alive(void *arg) 180a1eda741SJohn Baldwin { 181a1eda741SJohn Baldwin struct nvmf_softc *sc = arg; 182a1eda741SJohn Baldwin int traffic; 183a1eda741SJohn Baldwin 184a1eda741SJohn Baldwin /* 185a1eda741SJohn Baldwin * Don't bother sending a KeepAlive command if TKAS is active 186a1eda741SJohn Baldwin * and another command has been sent during the interval. 187a1eda741SJohn Baldwin */ 188a1eda741SJohn Baldwin traffic = atomic_load_int(&sc->ka_active_tx_traffic); 189a1eda741SJohn Baldwin if (traffic == 0 && !nvmf_cmd_keep_alive(sc, nvmf_keep_alive_complete, 190a1eda741SJohn Baldwin sc, M_NOWAIT)) 191a1eda741SJohn Baldwin device_printf(sc->dev, 192a1eda741SJohn Baldwin "Failed to allocate KeepAlive command\n"); 193a1eda741SJohn Baldwin 194a1eda741SJohn Baldwin /* Clear ka_active_tx_traffic after sending the keep alive command. */ 195a1eda741SJohn Baldwin atomic_store_int(&sc->ka_active_tx_traffic, 0); 196a1eda741SJohn Baldwin 197a1eda741SJohn Baldwin callout_schedule_sbt(&sc->ka_tx_timer, sc->ka_tx_sbt, 0, C_HARDCLOCK); 198a1eda741SJohn Baldwin } 199a1eda741SJohn Baldwin 200a1eda741SJohn Baldwin int 201365b89e8SJohn Baldwin nvmf_copyin_handoff(const struct nvmf_ioc_nv *nv, nvlist_t **nvlp) 202a1eda741SJohn Baldwin { 203*8bba2c0fSJohn Baldwin const struct nvme_discovery_log_entry *dle; 204*8bba2c0fSJohn Baldwin const struct nvme_controller_data *cdata; 205365b89e8SJohn Baldwin const nvlist_t *const *io; 206*8bba2c0fSJohn Baldwin const nvlist_t *admin, *rparams; 207365b89e8SJohn Baldwin nvlist_t *nvl; 208365b89e8SJohn Baldwin size_t i, num_io_queues; 209365b89e8SJohn Baldwin uint32_t qsize; 210a1eda741SJohn Baldwin int error; 211a1eda741SJohn Baldwin 212365b89e8SJohn Baldwin error = nvmf_unpack_ioc_nvlist(nv, &nvl); 213a1eda741SJohn Baldwin if (error != 0) 214365b89e8SJohn Baldwin return (error); 215a1eda741SJohn Baldwin 216365b89e8SJohn Baldwin if (!nvlist_exists_number(nvl, "trtype") || 217365b89e8SJohn Baldwin !nvlist_exists_nvlist(nvl, "admin") || 218365b89e8SJohn Baldwin !nvlist_exists_nvlist_array(nvl, "io") || 219*8bba2c0fSJohn Baldwin !nvlist_exists_binary(nvl, "cdata") || 220*8bba2c0fSJohn Baldwin !nvlist_exists_nvlist(nvl, "rparams")) 221*8bba2c0fSJohn Baldwin goto invalid; 222*8bba2c0fSJohn Baldwin 223*8bba2c0fSJohn Baldwin rparams = nvlist_get_nvlist(nvl, "rparams"); 224*8bba2c0fSJohn Baldwin if (!nvlist_exists_binary(rparams, "dle") || 225*8bba2c0fSJohn Baldwin !nvlist_exists_string(rparams, "hostnqn") || 226*8bba2c0fSJohn Baldwin !nvlist_exists_number(rparams, "num_io_queues") || 227*8bba2c0fSJohn Baldwin !nvlist_exists_number(rparams, "io_qsize")) 228365b89e8SJohn Baldwin goto invalid; 229365b89e8SJohn Baldwin 230365b89e8SJohn Baldwin admin = nvlist_get_nvlist(nvl, "admin"); 231365b89e8SJohn Baldwin if (!nvmf_validate_qpair_nvlist(admin, false)) 232365b89e8SJohn Baldwin goto invalid; 233365b89e8SJohn Baldwin if (!nvlist_get_bool(admin, "admin")) 234365b89e8SJohn Baldwin goto invalid; 235365b89e8SJohn Baldwin 236365b89e8SJohn Baldwin io = nvlist_get_nvlist_array(nvl, "io", &num_io_queues); 237*8bba2c0fSJohn Baldwin if (num_io_queues < 1 || 238*8bba2c0fSJohn Baldwin num_io_queues != nvlist_get_number(rparams, "num_io_queues")) 239365b89e8SJohn Baldwin goto invalid; 240365b89e8SJohn Baldwin for (i = 0; i < num_io_queues; i++) { 241365b89e8SJohn Baldwin if (!nvmf_validate_qpair_nvlist(io[i], false)) 242365b89e8SJohn Baldwin goto invalid; 243a1eda741SJohn Baldwin } 244a1eda741SJohn Baldwin 245a1eda741SJohn Baldwin /* Require all I/O queues to be the same size. */ 246*8bba2c0fSJohn Baldwin qsize = nvlist_get_number(rparams, "io_qsize"); 247*8bba2c0fSJohn Baldwin for (i = 0; i < num_io_queues; i++) { 248365b89e8SJohn Baldwin if (nvlist_get_number(io[i], "qsize") != qsize) 249365b89e8SJohn Baldwin goto invalid; 250a1eda741SJohn Baldwin } 251a1eda741SJohn Baldwin 252*8bba2c0fSJohn Baldwin cdata = nvlist_get_binary(nvl, "cdata", &i); 253*8bba2c0fSJohn Baldwin if (i != sizeof(*cdata)) 254*8bba2c0fSJohn Baldwin goto invalid; 255*8bba2c0fSJohn Baldwin dle = nvlist_get_binary(rparams, "dle", &i); 256*8bba2c0fSJohn Baldwin if (i != sizeof(*dle)) 257*8bba2c0fSJohn Baldwin goto invalid; 258*8bba2c0fSJohn Baldwin 259*8bba2c0fSJohn Baldwin if (memcmp(dle->subnqn, cdata->subnqn, sizeof(cdata->subnqn)) != 0) 260365b89e8SJohn Baldwin goto invalid; 261365b89e8SJohn Baldwin 262365b89e8SJohn Baldwin *nvlp = nvl; 263a1eda741SJohn Baldwin return (0); 264365b89e8SJohn Baldwin invalid: 265365b89e8SJohn Baldwin nvlist_destroy(nvl); 266365b89e8SJohn Baldwin return (EINVAL); 267a1eda741SJohn Baldwin } 268a1eda741SJohn Baldwin 269a1eda741SJohn Baldwin static int 270a1eda741SJohn Baldwin nvmf_probe(device_t dev) 271a1eda741SJohn Baldwin { 272365b89e8SJohn Baldwin const nvlist_t *nvl = device_get_ivars(dev); 273365b89e8SJohn Baldwin const struct nvme_controller_data *cdata; 274a1eda741SJohn Baldwin 275365b89e8SJohn Baldwin if (nvl == NULL) 276a1eda741SJohn Baldwin return (ENXIO); 277a1eda741SJohn Baldwin 278365b89e8SJohn Baldwin cdata = nvlist_get_binary(nvl, "cdata", NULL); 279365b89e8SJohn Baldwin device_set_descf(dev, "Fabrics: %.256s", cdata->subnqn); 280a1eda741SJohn Baldwin return (BUS_PROBE_DEFAULT); 281a1eda741SJohn Baldwin } 282a1eda741SJohn Baldwin 283a1eda741SJohn Baldwin static int 284*8bba2c0fSJohn Baldwin nvmf_establish_connection(struct nvmf_softc *sc, nvlist_t *nvl) 285a1eda741SJohn Baldwin { 286365b89e8SJohn Baldwin const nvlist_t *const *io; 287365b89e8SJohn Baldwin const nvlist_t *admin; 288365b89e8SJohn Baldwin uint64_t kato; 289365b89e8SJohn Baldwin size_t num_io_queues; 290365b89e8SJohn Baldwin enum nvmf_trtype trtype; 291a1eda741SJohn Baldwin char name[16]; 292a1eda741SJohn Baldwin 293365b89e8SJohn Baldwin trtype = nvlist_get_number(nvl, "trtype"); 294365b89e8SJohn Baldwin admin = nvlist_get_nvlist(nvl, "admin"); 295365b89e8SJohn Baldwin io = nvlist_get_nvlist_array(nvl, "io", &num_io_queues); 296365b89e8SJohn Baldwin kato = dnvlist_get_number(nvl, "kato", 0); 297365b89e8SJohn Baldwin 298a1eda741SJohn Baldwin /* Setup the admin queue. */ 299365b89e8SJohn Baldwin sc->admin = nvmf_init_qp(sc, trtype, admin, "admin queue", 0); 300a1eda741SJohn Baldwin if (sc->admin == NULL) { 301a1eda741SJohn Baldwin device_printf(sc->dev, "Failed to setup admin queue\n"); 302a1eda741SJohn Baldwin return (ENXIO); 303a1eda741SJohn Baldwin } 304a1eda741SJohn Baldwin 305a1eda741SJohn Baldwin /* Setup I/O queues. */ 306365b89e8SJohn Baldwin sc->io = malloc(num_io_queues * sizeof(*sc->io), M_NVMF, 307a1eda741SJohn Baldwin M_WAITOK | M_ZERO); 308365b89e8SJohn Baldwin sc->num_io_queues = num_io_queues; 309a1eda741SJohn Baldwin for (u_int i = 0; i < sc->num_io_queues; i++) { 310a1eda741SJohn Baldwin snprintf(name, sizeof(name), "I/O queue %u", i); 311365b89e8SJohn Baldwin sc->io[i] = nvmf_init_qp(sc, trtype, io[i], name, i); 312a1eda741SJohn Baldwin if (sc->io[i] == NULL) { 313a1eda741SJohn Baldwin device_printf(sc->dev, "Failed to setup I/O queue %u\n", 314*8bba2c0fSJohn Baldwin i); 315a1eda741SJohn Baldwin return (ENXIO); 316a1eda741SJohn Baldwin } 317a1eda741SJohn Baldwin } 318a1eda741SJohn Baldwin 319a1eda741SJohn Baldwin /* Start KeepAlive timers. */ 320365b89e8SJohn Baldwin if (kato != 0) { 321a1eda741SJohn Baldwin sc->ka_traffic = NVMEV(NVME_CTRLR_DATA_CTRATT_TBKAS, 322a1eda741SJohn Baldwin sc->cdata->ctratt) != 0; 323365b89e8SJohn Baldwin sc->ka_rx_sbt = mstosbt(kato); 324a1eda741SJohn Baldwin sc->ka_tx_sbt = sc->ka_rx_sbt / 2; 325a1eda741SJohn Baldwin callout_reset_sbt(&sc->ka_rx_timer, sc->ka_rx_sbt, 0, 326a1eda741SJohn Baldwin nvmf_check_keep_alive, sc, C_HARDCLOCK); 327a1eda741SJohn Baldwin callout_reset_sbt(&sc->ka_tx_timer, sc->ka_tx_sbt, 0, 328a1eda741SJohn Baldwin nvmf_send_keep_alive, sc, C_HARDCLOCK); 329a1eda741SJohn Baldwin } 330a1eda741SJohn Baldwin 331365b89e8SJohn Baldwin memcpy(sc->cdata, nvlist_get_binary(nvl, "cdata", NULL), 332365b89e8SJohn Baldwin sizeof(*sc->cdata)); 333365b89e8SJohn Baldwin 334*8bba2c0fSJohn Baldwin /* Save reconnect parameters. */ 335*8bba2c0fSJohn Baldwin nvlist_destroy(sc->rparams); 336*8bba2c0fSJohn Baldwin sc->rparams = nvlist_take_nvlist(nvl, "rparams"); 337*8bba2c0fSJohn Baldwin 338a1eda741SJohn Baldwin return (0); 339a1eda741SJohn Baldwin } 340a1eda741SJohn Baldwin 34102ddb305SJohn Baldwin typedef bool nvmf_scan_active_ns_cb(struct nvmf_softc *, uint32_t, 34202ddb305SJohn Baldwin const struct nvme_namespace_data *, void *); 34302ddb305SJohn Baldwin 344a1eda741SJohn Baldwin static bool 34502ddb305SJohn Baldwin nvmf_scan_active_nslist(struct nvmf_softc *sc, struct nvme_ns_list *nslist, 34602ddb305SJohn Baldwin struct nvme_namespace_data *data, uint32_t *nsidp, 34702ddb305SJohn Baldwin nvmf_scan_active_ns_cb *cb, void *cb_arg) 348a1eda741SJohn Baldwin { 349a1eda741SJohn Baldwin struct nvmf_completion_status status; 350a1eda741SJohn Baldwin uint32_t nsid; 351a1eda741SJohn Baldwin 352a1eda741SJohn Baldwin nvmf_status_init(&status); 353a1eda741SJohn Baldwin nvmf_status_wait_io(&status); 354a1eda741SJohn Baldwin if (!nvmf_cmd_identify_active_namespaces(sc, *nsidp, nslist, 355a1eda741SJohn Baldwin nvmf_complete, &status, nvmf_io_complete, &status, M_WAITOK)) { 356a1eda741SJohn Baldwin device_printf(sc->dev, 357a1eda741SJohn Baldwin "failed to send IDENTIFY active namespaces command\n"); 358a1eda741SJohn Baldwin return (false); 359a1eda741SJohn Baldwin } 360a1eda741SJohn Baldwin nvmf_wait_for_reply(&status); 361a1eda741SJohn Baldwin 362a1eda741SJohn Baldwin if (status.cqe.status != 0) { 363a1eda741SJohn Baldwin device_printf(sc->dev, 364a1eda741SJohn Baldwin "IDENTIFY active namespaces failed, status %#x\n", 365a1eda741SJohn Baldwin le16toh(status.cqe.status)); 366a1eda741SJohn Baldwin return (false); 367a1eda741SJohn Baldwin } 368a1eda741SJohn Baldwin 369a1eda741SJohn Baldwin if (status.io_error != 0) { 370a1eda741SJohn Baldwin device_printf(sc->dev, 371a1eda741SJohn Baldwin "IDENTIFY active namespaces failed with I/O error %d\n", 372a1eda741SJohn Baldwin status.io_error); 373a1eda741SJohn Baldwin return (false); 374a1eda741SJohn Baldwin } 375a1eda741SJohn Baldwin 376a1eda741SJohn Baldwin for (u_int i = 0; i < nitems(nslist->ns); i++) { 377a1eda741SJohn Baldwin nsid = nslist->ns[i]; 378a1eda741SJohn Baldwin if (nsid == 0) { 379a1eda741SJohn Baldwin *nsidp = 0; 380a1eda741SJohn Baldwin return (true); 381a1eda741SJohn Baldwin } 382a1eda741SJohn Baldwin 383a1eda741SJohn Baldwin nvmf_status_init(&status); 384a1eda741SJohn Baldwin nvmf_status_wait_io(&status); 385a1eda741SJohn Baldwin if (!nvmf_cmd_identify_namespace(sc, nsid, data, nvmf_complete, 386a1eda741SJohn Baldwin &status, nvmf_io_complete, &status, M_WAITOK)) { 387a1eda741SJohn Baldwin device_printf(sc->dev, 388a1eda741SJohn Baldwin "failed to send IDENTIFY namespace %u command\n", 389a1eda741SJohn Baldwin nsid); 390a1eda741SJohn Baldwin return (false); 391a1eda741SJohn Baldwin } 392a1eda741SJohn Baldwin nvmf_wait_for_reply(&status); 393a1eda741SJohn Baldwin 394a1eda741SJohn Baldwin if (status.cqe.status != 0) { 395a1eda741SJohn Baldwin device_printf(sc->dev, 396a1eda741SJohn Baldwin "IDENTIFY namespace %u failed, status %#x\n", nsid, 397a1eda741SJohn Baldwin le16toh(status.cqe.status)); 398a1eda741SJohn Baldwin return (false); 399a1eda741SJohn Baldwin } 400a1eda741SJohn Baldwin 401a1eda741SJohn Baldwin if (status.io_error != 0) { 402a1eda741SJohn Baldwin device_printf(sc->dev, 403a1eda741SJohn Baldwin "IDENTIFY namespace %u failed with I/O error %d\n", 404a1eda741SJohn Baldwin nsid, status.io_error); 405a1eda741SJohn Baldwin return (false); 406a1eda741SJohn Baldwin } 407a1eda741SJohn Baldwin 408a1eda741SJohn Baldwin nvme_namespace_data_swapbytes(data); 40902ddb305SJohn Baldwin if (!cb(sc, nsid, data, cb_arg)) 41002ddb305SJohn Baldwin return (false); 411a1eda741SJohn Baldwin } 412a1eda741SJohn Baldwin 413a1eda741SJohn Baldwin MPASS(nsid == nslist->ns[nitems(nslist->ns) - 1] && nsid != 0); 414a1eda741SJohn Baldwin 4158922c5b8SJohn Baldwin if (nsid >= NVME_GLOBAL_NAMESPACE_TAG - 1) 416a1eda741SJohn Baldwin *nsidp = 0; 417a1eda741SJohn Baldwin else 4188922c5b8SJohn Baldwin *nsidp = nsid; 419a1eda741SJohn Baldwin return (true); 420a1eda741SJohn Baldwin } 421a1eda741SJohn Baldwin 422a1eda741SJohn Baldwin static bool 42302ddb305SJohn Baldwin nvmf_scan_active_namespaces(struct nvmf_softc *sc, nvmf_scan_active_ns_cb *cb, 42402ddb305SJohn Baldwin void *cb_arg) 425a1eda741SJohn Baldwin { 426a1eda741SJohn Baldwin struct nvme_namespace_data *data; 427a1eda741SJohn Baldwin struct nvme_ns_list *nslist; 428a1eda741SJohn Baldwin uint32_t nsid; 429a1eda741SJohn Baldwin bool retval; 430a1eda741SJohn Baldwin 431a1eda741SJohn Baldwin nslist = malloc(sizeof(*nslist), M_NVMF, M_WAITOK); 432a1eda741SJohn Baldwin data = malloc(sizeof(*data), M_NVMF, M_WAITOK); 433a1eda741SJohn Baldwin 434a1eda741SJohn Baldwin nsid = 0; 435a1eda741SJohn Baldwin retval = true; 436a1eda741SJohn Baldwin for (;;) { 43702ddb305SJohn Baldwin if (!nvmf_scan_active_nslist(sc, nslist, data, &nsid, cb, 43802ddb305SJohn Baldwin cb_arg)) { 439a1eda741SJohn Baldwin retval = false; 440a1eda741SJohn Baldwin break; 441a1eda741SJohn Baldwin } 442a1eda741SJohn Baldwin if (nsid == 0) 443a1eda741SJohn Baldwin break; 444a1eda741SJohn Baldwin } 445a1eda741SJohn Baldwin 446a1eda741SJohn Baldwin free(data, M_NVMF); 447a1eda741SJohn Baldwin free(nslist, M_NVMF); 448a1eda741SJohn Baldwin return (retval); 449a1eda741SJohn Baldwin } 450a1eda741SJohn Baldwin 45102ddb305SJohn Baldwin static bool 45202ddb305SJohn Baldwin nvmf_add_ns(struct nvmf_softc *sc, uint32_t nsid, 45302ddb305SJohn Baldwin const struct nvme_namespace_data *data, void *arg __unused) 45402ddb305SJohn Baldwin { 45502ddb305SJohn Baldwin if (sc->ns[nsid - 1] != NULL) { 45602ddb305SJohn Baldwin device_printf(sc->dev, 45702ddb305SJohn Baldwin "duplicate namespace %u in active namespace list\n", 45802ddb305SJohn Baldwin nsid); 45902ddb305SJohn Baldwin return (false); 46002ddb305SJohn Baldwin } 46102ddb305SJohn Baldwin 46202ddb305SJohn Baldwin /* 46302ddb305SJohn Baldwin * As in nvme_ns_construct, a size of zero indicates an 46402ddb305SJohn Baldwin * invalid namespace. 46502ddb305SJohn Baldwin */ 46602ddb305SJohn Baldwin if (data->nsze == 0) { 46702ddb305SJohn Baldwin device_printf(sc->dev, 46802ddb305SJohn Baldwin "ignoring active namespace %u with zero size\n", nsid); 46902ddb305SJohn Baldwin return (true); 47002ddb305SJohn Baldwin } 47102ddb305SJohn Baldwin 47202ddb305SJohn Baldwin sc->ns[nsid - 1] = nvmf_init_ns(sc, nsid, data); 47302ddb305SJohn Baldwin 47402ddb305SJohn Baldwin nvmf_sim_rescan_ns(sc, nsid); 47502ddb305SJohn Baldwin return (true); 47602ddb305SJohn Baldwin } 47702ddb305SJohn Baldwin 47802ddb305SJohn Baldwin static bool 47902ddb305SJohn Baldwin nvmf_add_namespaces(struct nvmf_softc *sc) 48002ddb305SJohn Baldwin { 48102ddb305SJohn Baldwin sc->ns = mallocarray(sc->cdata->nn, sizeof(*sc->ns), M_NVMF, 48202ddb305SJohn Baldwin M_WAITOK | M_ZERO); 48302ddb305SJohn Baldwin return (nvmf_scan_active_namespaces(sc, nvmf_add_ns, NULL)); 48402ddb305SJohn Baldwin } 48502ddb305SJohn Baldwin 486a1eda741SJohn Baldwin static int 487a1eda741SJohn Baldwin nvmf_attach(device_t dev) 488a1eda741SJohn Baldwin { 489a1eda741SJohn Baldwin struct make_dev_args mda; 490a1eda741SJohn Baldwin struct nvmf_softc *sc = device_get_softc(dev); 491*8bba2c0fSJohn Baldwin nvlist_t *nvl = device_get_ivars(dev); 492365b89e8SJohn Baldwin const nvlist_t * const *io; 493931dd5feSJohn Baldwin struct sysctl_oid *oid; 494a1eda741SJohn Baldwin uint64_t val; 495a1eda741SJohn Baldwin u_int i; 496a1eda741SJohn Baldwin int error; 497a1eda741SJohn Baldwin 498365b89e8SJohn Baldwin if (nvl == NULL) 499a1eda741SJohn Baldwin return (ENXIO); 500a1eda741SJohn Baldwin 501a1eda741SJohn Baldwin sc->dev = dev; 502365b89e8SJohn Baldwin sc->trtype = nvlist_get_number(nvl, "trtype"); 503a1eda741SJohn Baldwin callout_init(&sc->ka_rx_timer, 1); 504a1eda741SJohn Baldwin callout_init(&sc->ka_tx_timer, 1); 505a1eda741SJohn Baldwin sx_init(&sc->connection_lock, "nvmf connection"); 506a1eda741SJohn Baldwin TASK_INIT(&sc->disconnect_task, 0, nvmf_disconnect_task, sc); 507a1eda741SJohn Baldwin 508931dd5feSJohn Baldwin oid = SYSCTL_ADD_NODE(device_get_sysctl_ctx(dev), 509931dd5feSJohn Baldwin SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), OID_AUTO, "ioq", 510931dd5feSJohn Baldwin CTLFLAG_RD | CTLFLAG_MPSAFE, NULL, "I/O Queues"); 511931dd5feSJohn Baldwin sc->ioq_oid_list = SYSCTL_CHILDREN(oid); 512931dd5feSJohn Baldwin 513365b89e8SJohn Baldwin sc->cdata = malloc(sizeof(*sc->cdata), M_NVMF, M_WAITOK); 514a1eda741SJohn Baldwin 515a1eda741SJohn Baldwin nvmf_init_aer(sc); 516a1eda741SJohn Baldwin 517365b89e8SJohn Baldwin error = nvmf_establish_connection(sc, nvl); 518a1eda741SJohn Baldwin if (error != 0) 519a1eda741SJohn Baldwin goto out; 520a1eda741SJohn Baldwin 521a1eda741SJohn Baldwin error = nvmf_read_property(sc, NVMF_PROP_CAP, 8, &sc->cap); 522a1eda741SJohn Baldwin if (error != 0) { 523a1eda741SJohn Baldwin device_printf(sc->dev, "Failed to fetch CAP\n"); 524a1eda741SJohn Baldwin error = ENXIO; 525a1eda741SJohn Baldwin goto out; 526a1eda741SJohn Baldwin } 527a1eda741SJohn Baldwin 528a1eda741SJohn Baldwin error = nvmf_read_property(sc, NVMF_PROP_VS, 4, &val); 529a1eda741SJohn Baldwin if (error != 0) { 530a1eda741SJohn Baldwin device_printf(sc->dev, "Failed to fetch VS\n"); 531a1eda741SJohn Baldwin error = ENXIO; 532a1eda741SJohn Baldwin goto out; 533a1eda741SJohn Baldwin } 534a1eda741SJohn Baldwin sc->vs = val; 535a1eda741SJohn Baldwin 536a1eda741SJohn Baldwin /* Honor MDTS if it is set. */ 537a1eda741SJohn Baldwin sc->max_xfer_size = maxphys; 538a1eda741SJohn Baldwin if (sc->cdata->mdts != 0) { 539a1eda741SJohn Baldwin sc->max_xfer_size = ulmin(sc->max_xfer_size, 540a1eda741SJohn Baldwin 1 << (sc->cdata->mdts + NVME_MPS_SHIFT + 541a1eda741SJohn Baldwin NVME_CAP_HI_MPSMIN(sc->cap >> 32))); 542a1eda741SJohn Baldwin } 543a1eda741SJohn Baldwin 544365b89e8SJohn Baldwin io = nvlist_get_nvlist_array(nvl, "io", NULL); 545365b89e8SJohn Baldwin sc->max_pending_io = nvlist_get_number(io[0], "qsize") * 546365b89e8SJohn Baldwin sc->num_io_queues; 5473ff90d91SJohn Baldwin 548a1eda741SJohn Baldwin error = nvmf_init_sim(sc); 549a1eda741SJohn Baldwin if (error != 0) 550a1eda741SJohn Baldwin goto out; 551a1eda741SJohn Baldwin 552a1eda741SJohn Baldwin error = nvmf_start_aer(sc); 553a1eda741SJohn Baldwin if (error != 0) { 554a1eda741SJohn Baldwin nvmf_destroy_sim(sc); 555a1eda741SJohn Baldwin goto out; 556a1eda741SJohn Baldwin } 557a1eda741SJohn Baldwin 558a1eda741SJohn Baldwin if (!nvmf_add_namespaces(sc)) { 559a1eda741SJohn Baldwin nvmf_destroy_sim(sc); 560a1eda741SJohn Baldwin goto out; 561a1eda741SJohn Baldwin } 562a1eda741SJohn Baldwin 563a1eda741SJohn Baldwin make_dev_args_init(&mda); 564a1eda741SJohn Baldwin mda.mda_devsw = &nvmf_cdevsw; 565a1eda741SJohn Baldwin mda.mda_uid = UID_ROOT; 566a1eda741SJohn Baldwin mda.mda_gid = GID_WHEEL; 567a1eda741SJohn Baldwin mda.mda_mode = 0600; 568a1eda741SJohn Baldwin mda.mda_si_drv1 = sc; 569a1eda741SJohn Baldwin error = make_dev_s(&mda, &sc->cdev, "%s", device_get_nameunit(dev)); 570a1eda741SJohn Baldwin if (error != 0) { 571a1eda741SJohn Baldwin nvmf_destroy_sim(sc); 572a1eda741SJohn Baldwin goto out; 573a1eda741SJohn Baldwin } 574a1eda741SJohn Baldwin 575f46d4971SJohn Baldwin sc->shutdown_pre_sync_eh = EVENTHANDLER_REGISTER(shutdown_pre_sync, 576f46d4971SJohn Baldwin nvmf_shutdown_pre_sync, sc, SHUTDOWN_PRI_FIRST); 577f46d4971SJohn Baldwin sc->shutdown_post_sync_eh = EVENTHANDLER_REGISTER(shutdown_post_sync, 5786751f65eSJohn Baldwin nvmf_shutdown_post_sync, sc, SHUTDOWN_PRI_LAST); 579f46d4971SJohn Baldwin 580a1eda741SJohn Baldwin return (0); 581a1eda741SJohn Baldwin out: 582a1eda741SJohn Baldwin if (sc->ns != NULL) { 583a1eda741SJohn Baldwin for (i = 0; i < sc->cdata->nn; i++) { 584a1eda741SJohn Baldwin if (sc->ns[i] != NULL) 585a1eda741SJohn Baldwin nvmf_destroy_ns(sc->ns[i]); 586a1eda741SJohn Baldwin } 587a1eda741SJohn Baldwin free(sc->ns, M_NVMF); 588a1eda741SJohn Baldwin } 589a1eda741SJohn Baldwin 590a1eda741SJohn Baldwin callout_drain(&sc->ka_tx_timer); 591a1eda741SJohn Baldwin callout_drain(&sc->ka_rx_timer); 592a1eda741SJohn Baldwin 593a1eda741SJohn Baldwin if (sc->admin != NULL) 594a1eda741SJohn Baldwin nvmf_shutdown_controller(sc); 595a1eda741SJohn Baldwin 596a1eda741SJohn Baldwin for (i = 0; i < sc->num_io_queues; i++) { 597a1eda741SJohn Baldwin if (sc->io[i] != NULL) 598a1eda741SJohn Baldwin nvmf_destroy_qp(sc->io[i]); 599a1eda741SJohn Baldwin } 600a1eda741SJohn Baldwin free(sc->io, M_NVMF); 601a1eda741SJohn Baldwin if (sc->admin != NULL) 602a1eda741SJohn Baldwin nvmf_destroy_qp(sc->admin); 603a1eda741SJohn Baldwin 604a1eda741SJohn Baldwin nvmf_destroy_aer(sc); 605a1eda741SJohn Baldwin 606a1eda741SJohn Baldwin taskqueue_drain(taskqueue_thread, &sc->disconnect_task); 607a1eda741SJohn Baldwin sx_destroy(&sc->connection_lock); 608*8bba2c0fSJohn Baldwin nvlist_destroy(sc->rparams); 609a1eda741SJohn Baldwin free(sc->cdata, M_NVMF); 610a1eda741SJohn Baldwin return (error); 611a1eda741SJohn Baldwin } 612a1eda741SJohn Baldwin 613a1eda741SJohn Baldwin void 614a1eda741SJohn Baldwin nvmf_disconnect(struct nvmf_softc *sc) 615a1eda741SJohn Baldwin { 616a1eda741SJohn Baldwin taskqueue_enqueue(taskqueue_thread, &sc->disconnect_task); 617a1eda741SJohn Baldwin } 618a1eda741SJohn Baldwin 619a1eda741SJohn Baldwin static void 620a1eda741SJohn Baldwin nvmf_disconnect_task(void *arg, int pending __unused) 621a1eda741SJohn Baldwin { 622a1eda741SJohn Baldwin struct nvmf_softc *sc = arg; 623a1eda741SJohn Baldwin u_int i; 624a1eda741SJohn Baldwin 625a1eda741SJohn Baldwin sx_xlock(&sc->connection_lock); 626a1eda741SJohn Baldwin if (sc->admin == NULL) { 627a1eda741SJohn Baldwin /* 628a1eda741SJohn Baldwin * Ignore transport errors if there is no active 629a1eda741SJohn Baldwin * association. 630a1eda741SJohn Baldwin */ 631a1eda741SJohn Baldwin sx_xunlock(&sc->connection_lock); 632a1eda741SJohn Baldwin return; 633a1eda741SJohn Baldwin } 634a1eda741SJohn Baldwin 635a1eda741SJohn Baldwin if (sc->detaching) { 636a1eda741SJohn Baldwin if (sc->admin != NULL) { 637a1eda741SJohn Baldwin /* 638a1eda741SJohn Baldwin * This unsticks the detach process if a 639a1eda741SJohn Baldwin * transport error occurs during detach. 640a1eda741SJohn Baldwin */ 641a1eda741SJohn Baldwin nvmf_shutdown_qp(sc->admin); 642a1eda741SJohn Baldwin } 643a1eda741SJohn Baldwin sx_xunlock(&sc->connection_lock); 644a1eda741SJohn Baldwin return; 645a1eda741SJohn Baldwin } 646a1eda741SJohn Baldwin 647a1eda741SJohn Baldwin if (sc->cdev == NULL) { 648a1eda741SJohn Baldwin /* 649a1eda741SJohn Baldwin * Transport error occurred during attach (nvmf_add_namespaces). 650a1eda741SJohn Baldwin * Shutdown the admin queue. 651a1eda741SJohn Baldwin */ 652a1eda741SJohn Baldwin nvmf_shutdown_qp(sc->admin); 653a1eda741SJohn Baldwin sx_xunlock(&sc->connection_lock); 654a1eda741SJohn Baldwin return; 655a1eda741SJohn Baldwin } 656a1eda741SJohn Baldwin 657a1eda741SJohn Baldwin callout_drain(&sc->ka_tx_timer); 658a1eda741SJohn Baldwin callout_drain(&sc->ka_rx_timer); 659a1eda741SJohn Baldwin sc->ka_traffic = false; 660a1eda741SJohn Baldwin 661a1eda741SJohn Baldwin /* Quiesce namespace consumers. */ 662a1eda741SJohn Baldwin nvmf_disconnect_sim(sc); 663a1eda741SJohn Baldwin for (i = 0; i < sc->cdata->nn; i++) { 664a1eda741SJohn Baldwin if (sc->ns[i] != NULL) 665a1eda741SJohn Baldwin nvmf_disconnect_ns(sc->ns[i]); 666a1eda741SJohn Baldwin } 667a1eda741SJohn Baldwin 668a1eda741SJohn Baldwin /* Shutdown the existing qpairs. */ 669a1eda741SJohn Baldwin for (i = 0; i < sc->num_io_queues; i++) { 670a1eda741SJohn Baldwin nvmf_destroy_qp(sc->io[i]); 671a1eda741SJohn Baldwin } 672a1eda741SJohn Baldwin free(sc->io, M_NVMF); 673a1eda741SJohn Baldwin sc->io = NULL; 674a1eda741SJohn Baldwin sc->num_io_queues = 0; 675a1eda741SJohn Baldwin nvmf_destroy_qp(sc->admin); 676a1eda741SJohn Baldwin sc->admin = NULL; 677a1eda741SJohn Baldwin 678a1eda741SJohn Baldwin sx_xunlock(&sc->connection_lock); 679a1eda741SJohn Baldwin } 680a1eda741SJohn Baldwin 681a1eda741SJohn Baldwin static int 682365b89e8SJohn Baldwin nvmf_reconnect_host(struct nvmf_softc *sc, struct nvmf_ioc_nv *nv) 683a1eda741SJohn Baldwin { 684365b89e8SJohn Baldwin const struct nvme_controller_data *cdata; 685365b89e8SJohn Baldwin nvlist_t *nvl; 686a1eda741SJohn Baldwin u_int i; 687a1eda741SJohn Baldwin int error; 688a1eda741SJohn Baldwin 689365b89e8SJohn Baldwin error = nvmf_copyin_handoff(nv, &nvl); 690365b89e8SJohn Baldwin if (error != 0) 691365b89e8SJohn Baldwin return (error); 692365b89e8SJohn Baldwin 693a1eda741SJohn Baldwin /* XXX: Should we permit changing the transport type? */ 694365b89e8SJohn Baldwin if (sc->trtype != nvlist_get_number(nvl, "trtype")) { 695a1eda741SJohn Baldwin device_printf(sc->dev, 696a1eda741SJohn Baldwin "transport type mismatch on reconnect\n"); 697a1eda741SJohn Baldwin return (EINVAL); 698a1eda741SJohn Baldwin } 699a1eda741SJohn Baldwin 700a1eda741SJohn Baldwin sx_xlock(&sc->connection_lock); 701a1eda741SJohn Baldwin if (sc->admin != NULL || sc->detaching) { 702a1eda741SJohn Baldwin error = EBUSY; 703a1eda741SJohn Baldwin goto out; 704a1eda741SJohn Baldwin } 705a1eda741SJohn Baldwin 706a1eda741SJohn Baldwin /* 707a1eda741SJohn Baldwin * Ensure this is for the same controller. Note that the 708a1eda741SJohn Baldwin * controller ID can vary across associations if the remote 709a1eda741SJohn Baldwin * system is using the dynamic controller model. This merely 710a1eda741SJohn Baldwin * ensures the new association is connected to the same NVMe 711a1eda741SJohn Baldwin * subsystem. 712a1eda741SJohn Baldwin */ 713365b89e8SJohn Baldwin cdata = nvlist_get_binary(nvl, "cdata", NULL); 714365b89e8SJohn Baldwin if (memcmp(sc->cdata->subnqn, cdata->subnqn, 715365b89e8SJohn Baldwin sizeof(cdata->subnqn)) != 0) { 716a1eda741SJohn Baldwin device_printf(sc->dev, 717a1eda741SJohn Baldwin "controller subsystem NQN mismatch on reconnect\n"); 718a1eda741SJohn Baldwin error = EINVAL; 719a1eda741SJohn Baldwin goto out; 720a1eda741SJohn Baldwin } 721a1eda741SJohn Baldwin 722a1eda741SJohn Baldwin /* 723a1eda741SJohn Baldwin * XXX: Require same number and size of I/O queues so that 724a1eda741SJohn Baldwin * max_pending_io is still correct? 725a1eda741SJohn Baldwin */ 726a1eda741SJohn Baldwin 727365b89e8SJohn Baldwin error = nvmf_establish_connection(sc, nvl); 728a1eda741SJohn Baldwin if (error != 0) 729a1eda741SJohn Baldwin goto out; 730a1eda741SJohn Baldwin 731a1eda741SJohn Baldwin error = nvmf_start_aer(sc); 732a1eda741SJohn Baldwin if (error != 0) 733a1eda741SJohn Baldwin goto out; 734a1eda741SJohn Baldwin 735a1eda741SJohn Baldwin device_printf(sc->dev, 736a1eda741SJohn Baldwin "established new association with %u I/O queues\n", 737a1eda741SJohn Baldwin sc->num_io_queues); 738a1eda741SJohn Baldwin 739a1eda741SJohn Baldwin /* Restart namespace consumers. */ 740a1eda741SJohn Baldwin for (i = 0; i < sc->cdata->nn; i++) { 741a1eda741SJohn Baldwin if (sc->ns[i] != NULL) 742a1eda741SJohn Baldwin nvmf_reconnect_ns(sc->ns[i]); 743a1eda741SJohn Baldwin } 744a1eda741SJohn Baldwin nvmf_reconnect_sim(sc); 745e140f85dSJohn Baldwin 746e140f85dSJohn Baldwin nvmf_rescan_all_ns(sc); 747a1eda741SJohn Baldwin out: 748a1eda741SJohn Baldwin sx_xunlock(&sc->connection_lock); 749365b89e8SJohn Baldwin nvlist_destroy(nvl); 750a1eda741SJohn Baldwin return (error); 751a1eda741SJohn Baldwin } 752a1eda741SJohn Baldwin 753f46d4971SJohn Baldwin static void 754f46d4971SJohn Baldwin nvmf_shutdown_pre_sync(void *arg, int howto) 755f46d4971SJohn Baldwin { 756f46d4971SJohn Baldwin struct nvmf_softc *sc = arg; 757f46d4971SJohn Baldwin 758f46d4971SJohn Baldwin if ((howto & RB_NOSYNC) != 0 || SCHEDULER_STOPPED()) 759f46d4971SJohn Baldwin return; 760f46d4971SJohn Baldwin 761f46d4971SJohn Baldwin /* 762f46d4971SJohn Baldwin * If this association is disconnected, abort any pending 763f46d4971SJohn Baldwin * requests with an error to permit filesystems to unmount 764f46d4971SJohn Baldwin * without hanging. 765f46d4971SJohn Baldwin */ 766f46d4971SJohn Baldwin sx_xlock(&sc->connection_lock); 767f46d4971SJohn Baldwin if (sc->admin != NULL || sc->detaching) { 768f46d4971SJohn Baldwin sx_xunlock(&sc->connection_lock); 769f46d4971SJohn Baldwin return; 770f46d4971SJohn Baldwin } 771f46d4971SJohn Baldwin 772f46d4971SJohn Baldwin for (u_int i = 0; i < sc->cdata->nn; i++) { 773f46d4971SJohn Baldwin if (sc->ns[i] != NULL) 774f46d4971SJohn Baldwin nvmf_shutdown_ns(sc->ns[i]); 775f46d4971SJohn Baldwin } 776f46d4971SJohn Baldwin nvmf_shutdown_sim(sc); 777f46d4971SJohn Baldwin sx_xunlock(&sc->connection_lock); 778f46d4971SJohn Baldwin } 779f46d4971SJohn Baldwin 780f46d4971SJohn Baldwin static void 781f46d4971SJohn Baldwin nvmf_shutdown_post_sync(void *arg, int howto) 782f46d4971SJohn Baldwin { 783f46d4971SJohn Baldwin struct nvmf_softc *sc = arg; 784f46d4971SJohn Baldwin 785f46d4971SJohn Baldwin if ((howto & RB_NOSYNC) != 0 || SCHEDULER_STOPPED()) 786f46d4971SJohn Baldwin return; 787f46d4971SJohn Baldwin 788f46d4971SJohn Baldwin /* 789f46d4971SJohn Baldwin * If this association is connected, disconnect gracefully. 790f46d4971SJohn Baldwin */ 791f46d4971SJohn Baldwin sx_xlock(&sc->connection_lock); 792f46d4971SJohn Baldwin if (sc->admin == NULL || sc->detaching) { 793f46d4971SJohn Baldwin sx_xunlock(&sc->connection_lock); 794f46d4971SJohn Baldwin return; 795f46d4971SJohn Baldwin } 796f46d4971SJohn Baldwin 797f46d4971SJohn Baldwin callout_drain(&sc->ka_tx_timer); 798f46d4971SJohn Baldwin callout_drain(&sc->ka_rx_timer); 799f46d4971SJohn Baldwin 800f46d4971SJohn Baldwin nvmf_shutdown_controller(sc); 8016751f65eSJohn Baldwin 8026751f65eSJohn Baldwin /* 8036751f65eSJohn Baldwin * Quiesce consumers so that any commands submitted after this 8046751f65eSJohn Baldwin * fail with an error. Notably, nda(4) calls nda_flush() from 8056751f65eSJohn Baldwin * a post_sync handler that might be ordered after this one. 8066751f65eSJohn Baldwin */ 8076751f65eSJohn Baldwin for (u_int i = 0; i < sc->cdata->nn; i++) { 8086751f65eSJohn Baldwin if (sc->ns[i] != NULL) 8096751f65eSJohn Baldwin nvmf_shutdown_ns(sc->ns[i]); 8106751f65eSJohn Baldwin } 8116751f65eSJohn Baldwin nvmf_shutdown_sim(sc); 8126751f65eSJohn Baldwin 813f46d4971SJohn Baldwin for (u_int i = 0; i < sc->num_io_queues; i++) { 814f46d4971SJohn Baldwin nvmf_destroy_qp(sc->io[i]); 815f46d4971SJohn Baldwin } 816f46d4971SJohn Baldwin nvmf_destroy_qp(sc->admin); 817f46d4971SJohn Baldwin sc->admin = NULL; 818f46d4971SJohn Baldwin sx_xunlock(&sc->connection_lock); 819f46d4971SJohn Baldwin } 820f46d4971SJohn Baldwin 821a1eda741SJohn Baldwin static int 822a1eda741SJohn Baldwin nvmf_detach(device_t dev) 823a1eda741SJohn Baldwin { 824a1eda741SJohn Baldwin struct nvmf_softc *sc = device_get_softc(dev); 825a1eda741SJohn Baldwin u_int i; 826a1eda741SJohn Baldwin 827a1eda741SJohn Baldwin destroy_dev(sc->cdev); 828a1eda741SJohn Baldwin 829a1eda741SJohn Baldwin sx_xlock(&sc->connection_lock); 830a1eda741SJohn Baldwin sc->detaching = true; 831a1eda741SJohn Baldwin sx_xunlock(&sc->connection_lock); 832a1eda741SJohn Baldwin 833f46d4971SJohn Baldwin EVENTHANDLER_DEREGISTER(shutdown_pre_sync, sc->shutdown_pre_sync_eh); 834a6ec2147SJohn Baldwin EVENTHANDLER_DEREGISTER(shutdown_post_sync, sc->shutdown_post_sync_eh); 835f46d4971SJohn Baldwin 836a1eda741SJohn Baldwin nvmf_destroy_sim(sc); 837a1eda741SJohn Baldwin for (i = 0; i < sc->cdata->nn; i++) { 838a1eda741SJohn Baldwin if (sc->ns[i] != NULL) 839a1eda741SJohn Baldwin nvmf_destroy_ns(sc->ns[i]); 840a1eda741SJohn Baldwin } 841a1eda741SJohn Baldwin free(sc->ns, M_NVMF); 842a1eda741SJohn Baldwin 843a1eda741SJohn Baldwin callout_drain(&sc->ka_tx_timer); 844a1eda741SJohn Baldwin callout_drain(&sc->ka_rx_timer); 845a1eda741SJohn Baldwin 846a1eda741SJohn Baldwin if (sc->admin != NULL) 847a1eda741SJohn Baldwin nvmf_shutdown_controller(sc); 848a1eda741SJohn Baldwin 849a1eda741SJohn Baldwin for (i = 0; i < sc->num_io_queues; i++) { 850a1eda741SJohn Baldwin nvmf_destroy_qp(sc->io[i]); 851a1eda741SJohn Baldwin } 852a1eda741SJohn Baldwin free(sc->io, M_NVMF); 853a1eda741SJohn Baldwin 854a1eda741SJohn Baldwin taskqueue_drain(taskqueue_thread, &sc->disconnect_task); 855a1eda741SJohn Baldwin 856a1eda741SJohn Baldwin if (sc->admin != NULL) 857a1eda741SJohn Baldwin nvmf_destroy_qp(sc->admin); 858a1eda741SJohn Baldwin 859a1eda741SJohn Baldwin nvmf_destroy_aer(sc); 860a1eda741SJohn Baldwin 861a1eda741SJohn Baldwin sx_destroy(&sc->connection_lock); 862*8bba2c0fSJohn Baldwin nvlist_destroy(sc->rparams); 863a1eda741SJohn Baldwin free(sc->cdata, M_NVMF); 864a1eda741SJohn Baldwin return (0); 865a1eda741SJohn Baldwin } 866a1eda741SJohn Baldwin 8678a082ca8SJohn Baldwin static void 8688a082ca8SJohn Baldwin nvmf_rescan_ns_1(struct nvmf_softc *sc, uint32_t nsid, 8698a082ca8SJohn Baldwin const struct nvme_namespace_data *data) 8708a082ca8SJohn Baldwin { 8718a082ca8SJohn Baldwin struct nvmf_namespace *ns; 8728a082ca8SJohn Baldwin 8738a082ca8SJohn Baldwin /* XXX: Needs locking around sc->ns[]. */ 8748a082ca8SJohn Baldwin ns = sc->ns[nsid - 1]; 8758a082ca8SJohn Baldwin if (data->nsze == 0) { 8768a082ca8SJohn Baldwin /* XXX: Needs locking */ 8778a082ca8SJohn Baldwin if (ns != NULL) { 8788a082ca8SJohn Baldwin nvmf_destroy_ns(ns); 8798a082ca8SJohn Baldwin sc->ns[nsid - 1] = NULL; 8808a082ca8SJohn Baldwin } 8818a082ca8SJohn Baldwin } else { 8828a082ca8SJohn Baldwin /* XXX: Needs locking */ 8838a082ca8SJohn Baldwin if (ns == NULL) { 8848a082ca8SJohn Baldwin sc->ns[nsid - 1] = nvmf_init_ns(sc, nsid, data); 8858a082ca8SJohn Baldwin } else { 8868a082ca8SJohn Baldwin if (!nvmf_update_ns(ns, data)) { 8878a082ca8SJohn Baldwin nvmf_destroy_ns(ns); 8888a082ca8SJohn Baldwin sc->ns[nsid - 1] = NULL; 8898a082ca8SJohn Baldwin } 8908a082ca8SJohn Baldwin } 8918a082ca8SJohn Baldwin } 8928a082ca8SJohn Baldwin 8938a082ca8SJohn Baldwin nvmf_sim_rescan_ns(sc, nsid); 8948a082ca8SJohn Baldwin } 8958a082ca8SJohn Baldwin 896a1eda741SJohn Baldwin void 897a1eda741SJohn Baldwin nvmf_rescan_ns(struct nvmf_softc *sc, uint32_t nsid) 898a1eda741SJohn Baldwin { 899a1eda741SJohn Baldwin struct nvmf_completion_status status; 900a1eda741SJohn Baldwin struct nvme_namespace_data *data; 901a1eda741SJohn Baldwin 902a1eda741SJohn Baldwin data = malloc(sizeof(*data), M_NVMF, M_WAITOK); 903a1eda741SJohn Baldwin 904a1eda741SJohn Baldwin nvmf_status_init(&status); 905a1eda741SJohn Baldwin nvmf_status_wait_io(&status); 906a1eda741SJohn Baldwin if (!nvmf_cmd_identify_namespace(sc, nsid, data, nvmf_complete, 907a1eda741SJohn Baldwin &status, nvmf_io_complete, &status, M_WAITOK)) { 908a1eda741SJohn Baldwin device_printf(sc->dev, 909a1eda741SJohn Baldwin "failed to send IDENTIFY namespace %u command\n", nsid); 910a1eda741SJohn Baldwin free(data, M_NVMF); 911a1eda741SJohn Baldwin return; 912a1eda741SJohn Baldwin } 913a1eda741SJohn Baldwin nvmf_wait_for_reply(&status); 914a1eda741SJohn Baldwin 915a1eda741SJohn Baldwin if (status.cqe.status != 0) { 916a1eda741SJohn Baldwin device_printf(sc->dev, 917a1eda741SJohn Baldwin "IDENTIFY namespace %u failed, status %#x\n", nsid, 918a1eda741SJohn Baldwin le16toh(status.cqe.status)); 919a1eda741SJohn Baldwin free(data, M_NVMF); 920a1eda741SJohn Baldwin return; 921a1eda741SJohn Baldwin } 922a1eda741SJohn Baldwin 923a1eda741SJohn Baldwin if (status.io_error != 0) { 924a1eda741SJohn Baldwin device_printf(sc->dev, 925a1eda741SJohn Baldwin "IDENTIFY namespace %u failed with I/O error %d\n", 926a1eda741SJohn Baldwin nsid, status.io_error); 927a1eda741SJohn Baldwin free(data, M_NVMF); 928a1eda741SJohn Baldwin return; 929a1eda741SJohn Baldwin } 930a1eda741SJohn Baldwin 931a1eda741SJohn Baldwin nvme_namespace_data_swapbytes(data); 932a1eda741SJohn Baldwin 9338a082ca8SJohn Baldwin nvmf_rescan_ns_1(sc, nsid, data); 934a1eda741SJohn Baldwin 935a1eda741SJohn Baldwin free(data, M_NVMF); 936a1eda741SJohn Baldwin } 937a1eda741SJohn Baldwin 938f6d434f1SJohn Baldwin static void 939f6d434f1SJohn Baldwin nvmf_purge_namespaces(struct nvmf_softc *sc, uint32_t first_nsid, 940f6d434f1SJohn Baldwin uint32_t next_valid_nsid) 941f6d434f1SJohn Baldwin { 942f6d434f1SJohn Baldwin struct nvmf_namespace *ns; 943f6d434f1SJohn Baldwin 944f6d434f1SJohn Baldwin for (uint32_t nsid = first_nsid; nsid < next_valid_nsid; nsid++) 945f6d434f1SJohn Baldwin { 946f6d434f1SJohn Baldwin /* XXX: Needs locking around sc->ns[]. */ 947f6d434f1SJohn Baldwin ns = sc->ns[nsid - 1]; 948f6d434f1SJohn Baldwin if (ns != NULL) { 949f6d434f1SJohn Baldwin nvmf_destroy_ns(ns); 950f6d434f1SJohn Baldwin sc->ns[nsid - 1] = NULL; 951f6d434f1SJohn Baldwin 952f6d434f1SJohn Baldwin nvmf_sim_rescan_ns(sc, nsid); 953f6d434f1SJohn Baldwin } 954f6d434f1SJohn Baldwin } 955f6d434f1SJohn Baldwin } 956f6d434f1SJohn Baldwin 957f6d434f1SJohn Baldwin static bool 958f6d434f1SJohn Baldwin nvmf_rescan_ns_cb(struct nvmf_softc *sc, uint32_t nsid, 959f6d434f1SJohn Baldwin const struct nvme_namespace_data *data, void *arg) 960f6d434f1SJohn Baldwin { 961f6d434f1SJohn Baldwin uint32_t *last_nsid = arg; 962f6d434f1SJohn Baldwin 963f6d434f1SJohn Baldwin /* Check for any gaps prior to this namespace. */ 964f6d434f1SJohn Baldwin nvmf_purge_namespaces(sc, *last_nsid + 1, nsid); 965f6d434f1SJohn Baldwin *last_nsid = nsid; 966f6d434f1SJohn Baldwin 967f6d434f1SJohn Baldwin nvmf_rescan_ns_1(sc, nsid, data); 968f6d434f1SJohn Baldwin return (true); 969f6d434f1SJohn Baldwin } 970f6d434f1SJohn Baldwin 971f6d434f1SJohn Baldwin void 972f6d434f1SJohn Baldwin nvmf_rescan_all_ns(struct nvmf_softc *sc) 973f6d434f1SJohn Baldwin { 974f6d434f1SJohn Baldwin uint32_t last_nsid; 975f6d434f1SJohn Baldwin 976f6d434f1SJohn Baldwin last_nsid = 0; 977f6d434f1SJohn Baldwin if (!nvmf_scan_active_namespaces(sc, nvmf_rescan_ns_cb, &last_nsid)) 978f6d434f1SJohn Baldwin return; 979f6d434f1SJohn Baldwin 980f6d434f1SJohn Baldwin /* 981f6d434f1SJohn Baldwin * Check for any namespace devices after the last active 982f6d434f1SJohn Baldwin * namespace. 983f6d434f1SJohn Baldwin */ 984f6d434f1SJohn Baldwin nvmf_purge_namespaces(sc, last_nsid + 1, sc->cdata->nn + 1); 985f6d434f1SJohn Baldwin } 986f6d434f1SJohn Baldwin 987a1eda741SJohn Baldwin int 988a1eda741SJohn Baldwin nvmf_passthrough_cmd(struct nvmf_softc *sc, struct nvme_pt_command *pt, 989a1eda741SJohn Baldwin bool admin) 990a1eda741SJohn Baldwin { 991a1eda741SJohn Baldwin struct nvmf_completion_status status; 992a1eda741SJohn Baldwin struct nvme_command cmd; 993a1eda741SJohn Baldwin struct memdesc mem; 994a1eda741SJohn Baldwin struct nvmf_host_qpair *qp; 995a1eda741SJohn Baldwin struct nvmf_request *req; 996a1eda741SJohn Baldwin void *buf; 997a1eda741SJohn Baldwin int error; 998a1eda741SJohn Baldwin 999a1eda741SJohn Baldwin if (pt->len > sc->max_xfer_size) 1000a1eda741SJohn Baldwin return (EINVAL); 1001a1eda741SJohn Baldwin 1002a1eda741SJohn Baldwin buf = NULL; 1003a1eda741SJohn Baldwin if (pt->len != 0) { 1004a1eda741SJohn Baldwin /* 1005a1eda741SJohn Baldwin * XXX: Depending on the size we may want to pin the 1006a1eda741SJohn Baldwin * user pages and use a memdesc with vm_page_t's 1007a1eda741SJohn Baldwin * instead. 1008a1eda741SJohn Baldwin */ 1009a1eda741SJohn Baldwin buf = malloc(pt->len, M_NVMF, M_WAITOK); 1010a1eda741SJohn Baldwin if (pt->is_read == 0) { 1011a1eda741SJohn Baldwin error = copyin(pt->buf, buf, pt->len); 1012a1eda741SJohn Baldwin if (error != 0) { 1013a1eda741SJohn Baldwin free(buf, M_NVMF); 1014a1eda741SJohn Baldwin return (error); 1015a1eda741SJohn Baldwin } 1016a1eda741SJohn Baldwin } else { 1017a1eda741SJohn Baldwin /* Ensure no kernel data is leaked to userland. */ 1018a1eda741SJohn Baldwin memset(buf, 0, pt->len); 1019a1eda741SJohn Baldwin } 1020a1eda741SJohn Baldwin } 1021a1eda741SJohn Baldwin 1022a1eda741SJohn Baldwin memset(&cmd, 0, sizeof(cmd)); 1023a1eda741SJohn Baldwin cmd.opc = pt->cmd.opc; 1024a1eda741SJohn Baldwin cmd.fuse = pt->cmd.fuse; 1025a1eda741SJohn Baldwin cmd.nsid = pt->cmd.nsid; 1026a1eda741SJohn Baldwin cmd.cdw10 = pt->cmd.cdw10; 1027a1eda741SJohn Baldwin cmd.cdw11 = pt->cmd.cdw11; 1028a1eda741SJohn Baldwin cmd.cdw12 = pt->cmd.cdw12; 1029a1eda741SJohn Baldwin cmd.cdw13 = pt->cmd.cdw13; 1030a1eda741SJohn Baldwin cmd.cdw14 = pt->cmd.cdw14; 1031a1eda741SJohn Baldwin cmd.cdw15 = pt->cmd.cdw15; 1032a1eda741SJohn Baldwin 1033d1516ec3SJohn Baldwin sx_slock(&sc->connection_lock); 1034d1516ec3SJohn Baldwin if (sc->admin == NULL || sc->detaching) { 1035d1516ec3SJohn Baldwin device_printf(sc->dev, 1036d1516ec3SJohn Baldwin "failed to send passthrough command\n"); 1037d1516ec3SJohn Baldwin error = ECONNABORTED; 1038d1516ec3SJohn Baldwin sx_sunlock(&sc->connection_lock); 1039d1516ec3SJohn Baldwin goto error; 1040d1516ec3SJohn Baldwin } 1041a1eda741SJohn Baldwin if (admin) 1042a1eda741SJohn Baldwin qp = sc->admin; 1043a1eda741SJohn Baldwin else 1044a1eda741SJohn Baldwin qp = nvmf_select_io_queue(sc); 1045a1eda741SJohn Baldwin nvmf_status_init(&status); 1046a1eda741SJohn Baldwin req = nvmf_allocate_request(qp, &cmd, nvmf_complete, &status, M_WAITOK); 1047d1516ec3SJohn Baldwin sx_sunlock(&sc->connection_lock); 1048a1eda741SJohn Baldwin if (req == NULL) { 1049a1eda741SJohn Baldwin device_printf(sc->dev, "failed to send passthrough command\n"); 1050a1eda741SJohn Baldwin error = ECONNABORTED; 1051a1eda741SJohn Baldwin goto error; 1052a1eda741SJohn Baldwin } 1053a1eda741SJohn Baldwin 1054a1eda741SJohn Baldwin if (pt->len != 0) { 1055a1eda741SJohn Baldwin mem = memdesc_vaddr(buf, pt->len); 1056a1eda741SJohn Baldwin nvmf_capsule_append_data(req->nc, &mem, pt->len, 1057a1eda741SJohn Baldwin pt->is_read == 0, nvmf_io_complete, &status); 1058a1eda741SJohn Baldwin nvmf_status_wait_io(&status); 1059a1eda741SJohn Baldwin } 1060a1eda741SJohn Baldwin 1061a1eda741SJohn Baldwin nvmf_submit_request(req); 1062a1eda741SJohn Baldwin nvmf_wait_for_reply(&status); 1063a1eda741SJohn Baldwin 1064a1eda741SJohn Baldwin memset(&pt->cpl, 0, sizeof(pt->cpl)); 1065a1eda741SJohn Baldwin pt->cpl.cdw0 = status.cqe.cdw0; 1066a1eda741SJohn Baldwin pt->cpl.status = status.cqe.status; 1067a1eda741SJohn Baldwin 1068a1eda741SJohn Baldwin error = status.io_error; 1069a1eda741SJohn Baldwin if (error == 0 && pt->len != 0 && pt->is_read != 0) 1070a1eda741SJohn Baldwin error = copyout(buf, pt->buf, pt->len); 1071a1eda741SJohn Baldwin error: 1072a1eda741SJohn Baldwin free(buf, M_NVMF); 1073a1eda741SJohn Baldwin return (error); 1074a1eda741SJohn Baldwin } 1075a1eda741SJohn Baldwin 1076a1eda741SJohn Baldwin static int 1077365b89e8SJohn Baldwin nvmf_reconnect_params(struct nvmf_softc *sc, struct nvmf_ioc_nv *nv) 1078365b89e8SJohn Baldwin { 1079365b89e8SJohn Baldwin int error; 1080365b89e8SJohn Baldwin 1081365b89e8SJohn Baldwin sx_slock(&sc->connection_lock); 1082*8bba2c0fSJohn Baldwin error = nvmf_pack_ioc_nvlist(sc->rparams, nv); 1083365b89e8SJohn Baldwin sx_sunlock(&sc->connection_lock); 1084365b89e8SJohn Baldwin 1085365b89e8SJohn Baldwin return (error); 1086365b89e8SJohn Baldwin } 1087365b89e8SJohn Baldwin 1088365b89e8SJohn Baldwin static int 1089a1eda741SJohn Baldwin nvmf_ioctl(struct cdev *cdev, u_long cmd, caddr_t arg, int flag, 1090a1eda741SJohn Baldwin struct thread *td) 1091a1eda741SJohn Baldwin { 1092a1eda741SJohn Baldwin struct nvmf_softc *sc = cdev->si_drv1; 1093a1eda741SJohn Baldwin struct nvme_get_nsid *gnsid; 1094a1eda741SJohn Baldwin struct nvme_pt_command *pt; 1095365b89e8SJohn Baldwin struct nvmf_ioc_nv *nv; 1096a1eda741SJohn Baldwin 1097a1eda741SJohn Baldwin switch (cmd) { 1098a1eda741SJohn Baldwin case NVME_PASSTHROUGH_CMD: 1099a1eda741SJohn Baldwin pt = (struct nvme_pt_command *)arg; 1100a1eda741SJohn Baldwin return (nvmf_passthrough_cmd(sc, pt, true)); 1101a1eda741SJohn Baldwin case NVME_GET_NSID: 1102a1eda741SJohn Baldwin gnsid = (struct nvme_get_nsid *)arg; 1103da4230afSJohn Baldwin strlcpy(gnsid->cdev, device_get_nameunit(sc->dev), 1104a1eda741SJohn Baldwin sizeof(gnsid->cdev)); 1105a1eda741SJohn Baldwin gnsid->nsid = 0; 1106a1eda741SJohn Baldwin return (0); 1107a1eda741SJohn Baldwin case NVME_GET_MAX_XFER_SIZE: 1108a1eda741SJohn Baldwin *(uint64_t *)arg = sc->max_xfer_size; 1109a1eda741SJohn Baldwin return (0); 1110a1eda741SJohn Baldwin case NVMF_RECONNECT_PARAMS: 1111365b89e8SJohn Baldwin nv = (struct nvmf_ioc_nv *)arg; 1112365b89e8SJohn Baldwin return (nvmf_reconnect_params(sc, nv)); 1113a1eda741SJohn Baldwin case NVMF_RECONNECT_HOST: 1114365b89e8SJohn Baldwin nv = (struct nvmf_ioc_nv *)arg; 1115365b89e8SJohn Baldwin return (nvmf_reconnect_host(sc, nv)); 1116a1eda741SJohn Baldwin default: 1117a1eda741SJohn Baldwin return (ENOTTY); 1118a1eda741SJohn Baldwin } 1119a1eda741SJohn Baldwin } 1120a1eda741SJohn Baldwin 1121a1eda741SJohn Baldwin static struct cdevsw nvmf_cdevsw = { 1122a1eda741SJohn Baldwin .d_version = D_VERSION, 1123a1eda741SJohn Baldwin .d_ioctl = nvmf_ioctl 1124a1eda741SJohn Baldwin }; 1125a1eda741SJohn Baldwin 1126a1eda741SJohn Baldwin static int 1127a1eda741SJohn Baldwin nvmf_modevent(module_t mod, int what, void *arg) 1128a1eda741SJohn Baldwin { 1129a1eda741SJohn Baldwin switch (what) { 1130a1eda741SJohn Baldwin case MOD_LOAD: 1131a1eda741SJohn Baldwin return (nvmf_ctl_load()); 1132a1eda741SJohn Baldwin case MOD_QUIESCE: 1133a1eda741SJohn Baldwin return (0); 1134a1eda741SJohn Baldwin case MOD_UNLOAD: 1135a1eda741SJohn Baldwin nvmf_ctl_unload(); 1136a1eda741SJohn Baldwin destroy_dev_drain(&nvmf_cdevsw); 1137a1eda741SJohn Baldwin return (0); 1138a1eda741SJohn Baldwin default: 1139a1eda741SJohn Baldwin return (EOPNOTSUPP); 1140a1eda741SJohn Baldwin } 1141a1eda741SJohn Baldwin } 1142a1eda741SJohn Baldwin 1143a1eda741SJohn Baldwin static device_method_t nvmf_methods[] = { 1144a1eda741SJohn Baldwin /* Device interface */ 1145a1eda741SJohn Baldwin DEVMETHOD(device_probe, nvmf_probe), 1146a1eda741SJohn Baldwin DEVMETHOD(device_attach, nvmf_attach), 1147a1eda741SJohn Baldwin DEVMETHOD(device_detach, nvmf_detach), 1148a1eda741SJohn Baldwin DEVMETHOD_END 1149a1eda741SJohn Baldwin }; 1150a1eda741SJohn Baldwin 1151a1eda741SJohn Baldwin driver_t nvme_nvmf_driver = { 1152a1eda741SJohn Baldwin "nvme", 1153a1eda741SJohn Baldwin nvmf_methods, 1154a1eda741SJohn Baldwin sizeof(struct nvmf_softc), 1155a1eda741SJohn Baldwin }; 1156a1eda741SJohn Baldwin 1157a1eda741SJohn Baldwin DRIVER_MODULE(nvme, root, nvme_nvmf_driver, nvmf_modevent, NULL); 1158a1eda741SJohn Baldwin MODULE_DEPEND(nvmf, nvmf_transport, 1, 1, 1); 1159