xref: /freebsd/sys/dev/nvmf/host/nvmf_ctldev.c (revision 365b89e8ea4af34a05f68aa28e77573e89fa00b2)
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