1a1eda741SJohn Baldwin /*- 2a1eda741SJohn Baldwin * SPDX-License-Identifier: BSD-2-Clause 3a1eda741SJohn Baldwin * 4a1eda741SJohn Baldwin * Copyright (c) 2023 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> 11a1eda741SJohn Baldwin #include <sys/malloc.h> 12*365b89e8SJohn Baldwin #include <sys/nv.h> 13a1eda741SJohn Baldwin #include <dev/nvme/nvme.h> 14a1eda741SJohn Baldwin #include <dev/nvmf/nvmf.h> 15a1eda741SJohn Baldwin #include <dev/nvmf/nvmf_transport.h> 16a1eda741SJohn Baldwin #include <dev/nvmf/host/nvmf_var.h> 17a1eda741SJohn Baldwin 18a1eda741SJohn Baldwin static struct cdev *nvmf_cdev; 19a1eda741SJohn Baldwin 20a1eda741SJohn Baldwin static int 21*365b89e8SJohn Baldwin nvmf_handoff_host(struct nvmf_ioc_nv *nv) 22a1eda741SJohn Baldwin { 23*365b89e8SJohn Baldwin nvlist_t *nvl; 24a1eda741SJohn Baldwin device_t dev; 25a1eda741SJohn Baldwin int error; 26a1eda741SJohn Baldwin 27*365b89e8SJohn Baldwin error = nvmf_copyin_handoff(nv, &nvl); 28a1eda741SJohn Baldwin if (error != 0) 29a1eda741SJohn Baldwin return (error); 30a1eda741SJohn Baldwin 31a1eda741SJohn Baldwin bus_topo_lock(); 32a1eda741SJohn Baldwin dev = device_add_child(root_bus, "nvme", -1); 33a1eda741SJohn Baldwin if (dev == NULL) { 34a1eda741SJohn Baldwin bus_topo_unlock(); 35a1eda741SJohn Baldwin error = ENXIO; 36a1eda741SJohn Baldwin goto out; 37a1eda741SJohn Baldwin } 38a1eda741SJohn Baldwin 39*365b89e8SJohn Baldwin device_set_ivars(dev, nvl); 40a1eda741SJohn Baldwin error = device_probe_and_attach(dev); 41a1eda741SJohn Baldwin device_set_ivars(dev, NULL); 42a1eda741SJohn Baldwin if (error != 0) 43a1eda741SJohn Baldwin device_delete_child(root_bus, dev); 44a1eda741SJohn Baldwin bus_topo_unlock(); 45a1eda741SJohn Baldwin 46a1eda741SJohn Baldwin out: 47*365b89e8SJohn Baldwin nvlist_destroy(nvl); 48a1eda741SJohn Baldwin return (error); 49a1eda741SJohn Baldwin } 50a1eda741SJohn Baldwin 51a1eda741SJohn Baldwin static bool 52a1eda741SJohn Baldwin nvmf_matches(device_t dev, char *name) 53a1eda741SJohn Baldwin { 54a1eda741SJohn Baldwin struct nvmf_softc *sc = device_get_softc(dev); 55a1eda741SJohn Baldwin 56a1eda741SJohn Baldwin if (strcmp(device_get_nameunit(dev), name) == 0) 57a1eda741SJohn Baldwin return (true); 58a1eda741SJohn Baldwin if (strcmp(sc->cdata->subnqn, name) == 0) 59a1eda741SJohn Baldwin return (true); 60a1eda741SJohn Baldwin return (false); 61a1eda741SJohn Baldwin } 62a1eda741SJohn Baldwin 63a1eda741SJohn Baldwin static int 64a1eda741SJohn Baldwin nvmf_disconnect_by_name(char *name) 65a1eda741SJohn Baldwin { 66a1eda741SJohn Baldwin devclass_t dc; 67a1eda741SJohn Baldwin device_t dev; 68a1eda741SJohn Baldwin int error, unit; 69a1eda741SJohn Baldwin bool found; 70a1eda741SJohn Baldwin 71a1eda741SJohn Baldwin found = false; 72a1eda741SJohn Baldwin error = 0; 73a1eda741SJohn Baldwin bus_topo_lock(); 74a1eda741SJohn Baldwin dc = devclass_find("nvme"); 75a1eda741SJohn Baldwin if (dc == NULL) 76a1eda741SJohn Baldwin goto out; 77a1eda741SJohn Baldwin 78a1eda741SJohn Baldwin for (unit = 0; unit < devclass_get_maxunit(dc); unit++) { 79a1eda741SJohn Baldwin dev = devclass_get_device(dc, unit); 80a1eda741SJohn Baldwin if (dev == NULL) 81a1eda741SJohn Baldwin continue; 82a1eda741SJohn Baldwin if (device_get_driver(dev) != &nvme_nvmf_driver) 83a1eda741SJohn Baldwin continue; 84a1eda741SJohn Baldwin if (device_get_parent(dev) != root_bus) 85a1eda741SJohn Baldwin continue; 86a1eda741SJohn Baldwin if (name != NULL && !nvmf_matches(dev, name)) 87a1eda741SJohn Baldwin continue; 88a1eda741SJohn Baldwin 89a1eda741SJohn Baldwin error = device_delete_child(root_bus, dev); 90a1eda741SJohn Baldwin if (error != 0) 91a1eda741SJohn Baldwin break; 92a1eda741SJohn Baldwin found = true; 93a1eda741SJohn Baldwin } 94a1eda741SJohn Baldwin out: 95a1eda741SJohn Baldwin bus_topo_unlock(); 96a1eda741SJohn Baldwin if (error == 0 && !found) 97a1eda741SJohn Baldwin error = ENOENT; 98a1eda741SJohn Baldwin return (error); 99a1eda741SJohn Baldwin } 100a1eda741SJohn Baldwin 101a1eda741SJohn Baldwin static int 102a1eda741SJohn Baldwin nvmf_disconnect_host(const char **namep) 103a1eda741SJohn Baldwin { 104a1eda741SJohn Baldwin char *name; 105a1eda741SJohn Baldwin int error; 106a1eda741SJohn Baldwin 107a1eda741SJohn Baldwin name = malloc(PATH_MAX, M_NVMF, M_WAITOK); 108a1eda741SJohn Baldwin error = copyinstr(*namep, name, PATH_MAX, NULL); 109a1eda741SJohn Baldwin if (error == 0) 110a1eda741SJohn Baldwin error = nvmf_disconnect_by_name(name); 111a1eda741SJohn Baldwin free(name, M_NVMF); 112a1eda741SJohn Baldwin return (error); 113a1eda741SJohn Baldwin } 114a1eda741SJohn Baldwin 115a1eda741SJohn Baldwin static int 116a1eda741SJohn Baldwin nvmf_ctl_ioctl(struct cdev *dev, u_long cmd, caddr_t arg, int flag, 117a1eda741SJohn Baldwin struct thread *td) 118a1eda741SJohn Baldwin { 119a1eda741SJohn Baldwin switch (cmd) { 120a1eda741SJohn Baldwin case NVMF_HANDOFF_HOST: 121*365b89e8SJohn Baldwin return (nvmf_handoff_host((struct nvmf_ioc_nv *)arg)); 122a1eda741SJohn Baldwin case NVMF_DISCONNECT_HOST: 123a1eda741SJohn Baldwin return (nvmf_disconnect_host((const char **)arg)); 124a1eda741SJohn Baldwin case NVMF_DISCONNECT_ALL: 125a1eda741SJohn Baldwin return (nvmf_disconnect_by_name(NULL)); 126a1eda741SJohn Baldwin default: 127a1eda741SJohn Baldwin return (ENOTTY); 128a1eda741SJohn Baldwin } 129a1eda741SJohn Baldwin } 130a1eda741SJohn Baldwin 131a1eda741SJohn Baldwin static struct cdevsw nvmf_ctl_cdevsw = { 132a1eda741SJohn Baldwin .d_version = D_VERSION, 133a1eda741SJohn Baldwin .d_ioctl = nvmf_ctl_ioctl 134a1eda741SJohn Baldwin }; 135a1eda741SJohn Baldwin 136a1eda741SJohn Baldwin int 137a1eda741SJohn Baldwin nvmf_ctl_load(void) 138a1eda741SJohn Baldwin { 139a1eda741SJohn Baldwin struct make_dev_args mda; 140a1eda741SJohn Baldwin int error; 141a1eda741SJohn Baldwin 142a1eda741SJohn Baldwin make_dev_args_init(&mda); 143a1eda741SJohn Baldwin mda.mda_devsw = &nvmf_ctl_cdevsw; 144a1eda741SJohn Baldwin mda.mda_uid = UID_ROOT; 145a1eda741SJohn Baldwin mda.mda_gid = GID_WHEEL; 146a1eda741SJohn Baldwin mda.mda_mode = 0600; 147a1eda741SJohn Baldwin error = make_dev_s(&mda, &nvmf_cdev, "nvmf"); 148a1eda741SJohn Baldwin if (error != 0) 149a1eda741SJohn Baldwin nvmf_cdev = NULL; 150a1eda741SJohn Baldwin return (error); 151a1eda741SJohn Baldwin } 152a1eda741SJohn Baldwin 153a1eda741SJohn Baldwin void 154a1eda741SJohn Baldwin nvmf_ctl_unload(void) 155a1eda741SJohn Baldwin { 156a1eda741SJohn Baldwin if (nvmf_cdev != NULL) { 157a1eda741SJohn Baldwin destroy_dev(nvmf_cdev); 158a1eda741SJohn Baldwin nvmf_cdev = NULL; 159a1eda741SJohn Baldwin } 160a1eda741SJohn Baldwin } 161