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
nvmf_handoff_host(struct nvmf_ioc_nv * nv)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
nvmf_matches(device_t dev,char * name)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
nvmf_disconnect_by_name(char * name)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
nvmf_disconnect_host(const char ** namep)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
nvmf_ctl_ioctl(struct cdev * dev,u_long cmd,caddr_t arg,int flag,struct thread * td)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
nvmf_ctl_load(void)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
nvmf_ctl_unload(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