xref: /openbmc/linux/drivers/xen/xenbus/xenbus_probe_backend.c (revision df660251eb534649f90f9dcfe1da1cef4ea48a3e)
1*df660251SIan Campbell /******************************************************************************
2*df660251SIan Campbell  * Talks to Xen Store to figure out what devices we have (backend half).
3*df660251SIan Campbell  *
4*df660251SIan Campbell  * Copyright (C) 2005 Rusty Russell, IBM Corporation
5*df660251SIan Campbell  * Copyright (C) 2005 Mike Wray, Hewlett-Packard
6*df660251SIan Campbell  * Copyright (C) 2005, 2006 XenSource Ltd
7*df660251SIan Campbell  * Copyright (C) 2007 Solarflare Communications, Inc.
8*df660251SIan Campbell  *
9*df660251SIan Campbell  * This program is free software; you can redistribute it and/or
10*df660251SIan Campbell  * modify it under the terms of the GNU General Public License version 2
11*df660251SIan Campbell  * as published by the Free Software Foundation; or, when distributed
12*df660251SIan Campbell  * separately from the Linux kernel or incorporated into other
13*df660251SIan Campbell  * software packages, subject to the following license:
14*df660251SIan Campbell  *
15*df660251SIan Campbell  * Permission is hereby granted, free of charge, to any person obtaining a copy
16*df660251SIan Campbell  * of this source file (the "Software"), to deal in the Software without
17*df660251SIan Campbell  * restriction, including without limitation the rights to use, copy, modify,
18*df660251SIan Campbell  * merge, publish, distribute, sublicense, and/or sell copies of the Software,
19*df660251SIan Campbell  * and to permit persons to whom the Software is furnished to do so, subject to
20*df660251SIan Campbell  * the following conditions:
21*df660251SIan Campbell  *
22*df660251SIan Campbell  * The above copyright notice and this permission notice shall be included in
23*df660251SIan Campbell  * all copies or substantial portions of the Software.
24*df660251SIan Campbell  *
25*df660251SIan Campbell  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
26*df660251SIan Campbell  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
27*df660251SIan Campbell  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
28*df660251SIan Campbell  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
29*df660251SIan Campbell  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
30*df660251SIan Campbell  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
31*df660251SIan Campbell  * IN THE SOFTWARE.
32*df660251SIan Campbell  */
33*df660251SIan Campbell 
34*df660251SIan Campbell #define DPRINTK(fmt, args...)				\
35*df660251SIan Campbell 	pr_debug("xenbus_probe (%s:%d) " fmt ".\n",	\
36*df660251SIan Campbell 		 __func__, __LINE__, ##args)
37*df660251SIan Campbell 
38*df660251SIan Campbell #include <linux/kernel.h>
39*df660251SIan Campbell #include <linux/err.h>
40*df660251SIan Campbell #include <linux/string.h>
41*df660251SIan Campbell #include <linux/ctype.h>
42*df660251SIan Campbell #include <linux/fcntl.h>
43*df660251SIan Campbell #include <linux/mm.h>
44*df660251SIan Campbell #include <linux/notifier.h>
45*df660251SIan Campbell 
46*df660251SIan Campbell #include <asm/page.h>
47*df660251SIan Campbell #include <asm/pgtable.h>
48*df660251SIan Campbell #include <asm/xen/hypervisor.h>
49*df660251SIan Campbell #include <asm/hypervisor.h>
50*df660251SIan Campbell #include <xen/xenbus.h>
51*df660251SIan Campbell #include <xen/evtchn.h>
52*df660251SIan Campbell #include <xen/features.h>
53*df660251SIan Campbell 
54*df660251SIan Campbell #include "xenbus_comms.h"
55*df660251SIan Campbell #include "xenbus_probe.h"
56*df660251SIan Campbell 
57*df660251SIan Campbell /* backend/<type>/<fe-uuid>/<id> => <type>-<fe-domid>-<id> */
58*df660251SIan Campbell static int backend_bus_id(char bus_id[XEN_BUS_ID_SIZE], const char *nodename)
59*df660251SIan Campbell {
60*df660251SIan Campbell 	int domid, err;
61*df660251SIan Campbell 	const char *devid, *type, *frontend;
62*df660251SIan Campbell 	unsigned int typelen;
63*df660251SIan Campbell 
64*df660251SIan Campbell 	type = strchr(nodename, '/');
65*df660251SIan Campbell 	if (!type)
66*df660251SIan Campbell 		return -EINVAL;
67*df660251SIan Campbell 	type++;
68*df660251SIan Campbell 	typelen = strcspn(type, "/");
69*df660251SIan Campbell 	if (!typelen || type[typelen] != '/')
70*df660251SIan Campbell 		return -EINVAL;
71*df660251SIan Campbell 
72*df660251SIan Campbell 	devid = strrchr(nodename, '/') + 1;
73*df660251SIan Campbell 
74*df660251SIan Campbell 	err = xenbus_gather(XBT_NIL, nodename, "frontend-id", "%i", &domid,
75*df660251SIan Campbell 			    "frontend", NULL, &frontend,
76*df660251SIan Campbell 			    NULL);
77*df660251SIan Campbell 	if (err)
78*df660251SIan Campbell 		return err;
79*df660251SIan Campbell 	if (strlen(frontend) == 0)
80*df660251SIan Campbell 		err = -ERANGE;
81*df660251SIan Campbell 	if (!err && !xenbus_exists(XBT_NIL, frontend, ""))
82*df660251SIan Campbell 		err = -ENOENT;
83*df660251SIan Campbell 	kfree(frontend);
84*df660251SIan Campbell 
85*df660251SIan Campbell 	if (err)
86*df660251SIan Campbell 		return err;
87*df660251SIan Campbell 
88*df660251SIan Campbell 	if (snprintf(bus_id, XEN_BUS_ID_SIZE,
89*df660251SIan Campbell 		     "%.*s-%i-%s", typelen, type, domid, devid) >= XEN_BUS_ID_SIZE)
90*df660251SIan Campbell 		return -ENOSPC;
91*df660251SIan Campbell 	return 0;
92*df660251SIan Campbell }
93*df660251SIan Campbell 
94*df660251SIan Campbell static int xenbus_uevent_backend(struct device *dev,
95*df660251SIan Campbell 				 struct kobj_uevent_env *env)
96*df660251SIan Campbell {
97*df660251SIan Campbell 	struct xenbus_device *xdev;
98*df660251SIan Campbell 	struct xenbus_driver *drv;
99*df660251SIan Campbell 	struct xen_bus_type *bus;
100*df660251SIan Campbell 
101*df660251SIan Campbell 	DPRINTK("");
102*df660251SIan Campbell 
103*df660251SIan Campbell 	if (dev == NULL)
104*df660251SIan Campbell 		return -ENODEV;
105*df660251SIan Campbell 
106*df660251SIan Campbell 	xdev = to_xenbus_device(dev);
107*df660251SIan Campbell 	bus = container_of(xdev->dev.bus, struct xen_bus_type, bus);
108*df660251SIan Campbell 	if (xdev == NULL)
109*df660251SIan Campbell 		return -ENODEV;
110*df660251SIan Campbell 
111*df660251SIan Campbell 	/* stuff we want to pass to /sbin/hotplug */
112*df660251SIan Campbell 	if (add_uevent_var(env, "XENBUS_TYPE=%s", xdev->devicetype))
113*df660251SIan Campbell 		return -ENOMEM;
114*df660251SIan Campbell 
115*df660251SIan Campbell 	if (add_uevent_var(env, "XENBUS_PATH=%s", xdev->nodename))
116*df660251SIan Campbell 		return -ENOMEM;
117*df660251SIan Campbell 
118*df660251SIan Campbell 	if (add_uevent_var(env, "XENBUS_BASE_PATH=%s", bus->root))
119*df660251SIan Campbell 		return -ENOMEM;
120*df660251SIan Campbell 
121*df660251SIan Campbell 	if (dev->driver) {
122*df660251SIan Campbell 		drv = to_xenbus_driver(dev->driver);
123*df660251SIan Campbell 		if (drv && drv->uevent)
124*df660251SIan Campbell 			return drv->uevent(xdev, env);
125*df660251SIan Campbell 	}
126*df660251SIan Campbell 
127*df660251SIan Campbell 	return 0;
128*df660251SIan Campbell }
129*df660251SIan Campbell 
130*df660251SIan Campbell /* backend/<typename>/<frontend-uuid>/<name> */
131*df660251SIan Campbell static int xenbus_probe_backend_unit(struct xen_bus_type *bus,
132*df660251SIan Campbell 				     const char *dir,
133*df660251SIan Campbell 				     const char *type,
134*df660251SIan Campbell 				     const char *name)
135*df660251SIan Campbell {
136*df660251SIan Campbell 	char *nodename;
137*df660251SIan Campbell 	int err;
138*df660251SIan Campbell 
139*df660251SIan Campbell 	nodename = kasprintf(GFP_KERNEL, "%s/%s", dir, name);
140*df660251SIan Campbell 	if (!nodename)
141*df660251SIan Campbell 		return -ENOMEM;
142*df660251SIan Campbell 
143*df660251SIan Campbell 	DPRINTK("%s\n", nodename);
144*df660251SIan Campbell 
145*df660251SIan Campbell 	err = xenbus_probe_node(bus, type, nodename);
146*df660251SIan Campbell 	kfree(nodename);
147*df660251SIan Campbell 	return err;
148*df660251SIan Campbell }
149*df660251SIan Campbell 
150*df660251SIan Campbell /* backend/<typename>/<frontend-domid> */
151*df660251SIan Campbell static int xenbus_probe_backend(struct xen_bus_type *bus, const char *type, const char *domid)
152*df660251SIan Campbell {
153*df660251SIan Campbell 	char *nodename;
154*df660251SIan Campbell 	int err = 0;
155*df660251SIan Campbell 	char **dir;
156*df660251SIan Campbell 	unsigned int i, dir_n = 0;
157*df660251SIan Campbell 
158*df660251SIan Campbell 	DPRINTK("");
159*df660251SIan Campbell 
160*df660251SIan Campbell 	nodename = kasprintf(GFP_KERNEL, "%s/%s/%s", bus->root, type, domid);
161*df660251SIan Campbell 	if (!nodename)
162*df660251SIan Campbell 		return -ENOMEM;
163*df660251SIan Campbell 
164*df660251SIan Campbell 	dir = xenbus_directory(XBT_NIL, nodename, "", &dir_n);
165*df660251SIan Campbell 	if (IS_ERR(dir)) {
166*df660251SIan Campbell 		kfree(nodename);
167*df660251SIan Campbell 		return PTR_ERR(dir);
168*df660251SIan Campbell 	}
169*df660251SIan Campbell 
170*df660251SIan Campbell 	for (i = 0; i < dir_n; i++) {
171*df660251SIan Campbell 		err = xenbus_probe_backend_unit(bus, nodename, type, dir[i]);
172*df660251SIan Campbell 		if (err)
173*df660251SIan Campbell 			break;
174*df660251SIan Campbell 	}
175*df660251SIan Campbell 	kfree(dir);
176*df660251SIan Campbell 	kfree(nodename);
177*df660251SIan Campbell 	return err;
178*df660251SIan Campbell }
179*df660251SIan Campbell 
180*df660251SIan Campbell static void frontend_changed(struct xenbus_watch *watch,
181*df660251SIan Campbell 			    const char **vec, unsigned int len)
182*df660251SIan Campbell {
183*df660251SIan Campbell 	xenbus_otherend_changed(watch, vec, len, 0);
184*df660251SIan Campbell }
185*df660251SIan Campbell 
186*df660251SIan Campbell static struct device_attribute xenbus_backend_dev_attrs[] = {
187*df660251SIan Campbell 	__ATTR_NULL
188*df660251SIan Campbell };
189*df660251SIan Campbell 
190*df660251SIan Campbell static struct xen_bus_type xenbus_backend = {
191*df660251SIan Campbell 	.root = "backend",
192*df660251SIan Campbell 	.levels = 3, 		/* backend/type/<frontend>/<id> */
193*df660251SIan Campbell 	.get_bus_id = backend_bus_id,
194*df660251SIan Campbell 	.probe = xenbus_probe_backend,
195*df660251SIan Campbell 	.otherend_changed = frontend_changed,
196*df660251SIan Campbell 	.bus = {
197*df660251SIan Campbell 		.name      = "xen-backend",
198*df660251SIan Campbell 		.match     = xenbus_match,
199*df660251SIan Campbell 		.uevent    = xenbus_uevent_backend,
200*df660251SIan Campbell 		.probe     = xenbus_dev_probe,
201*df660251SIan Campbell 		.remove    = xenbus_dev_remove,
202*df660251SIan Campbell 		.shutdown  = xenbus_dev_shutdown,
203*df660251SIan Campbell 		.dev_attrs = xenbus_backend_dev_attrs,
204*df660251SIan Campbell 	},
205*df660251SIan Campbell };
206*df660251SIan Campbell 
207*df660251SIan Campbell static void backend_changed(struct xenbus_watch *watch,
208*df660251SIan Campbell 			    const char **vec, unsigned int len)
209*df660251SIan Campbell {
210*df660251SIan Campbell 	DPRINTK("");
211*df660251SIan Campbell 
212*df660251SIan Campbell 	xenbus_dev_changed(vec[XS_WATCH_PATH], &xenbus_backend);
213*df660251SIan Campbell }
214*df660251SIan Campbell 
215*df660251SIan Campbell static struct xenbus_watch be_watch = {
216*df660251SIan Campbell 	.node = "backend",
217*df660251SIan Campbell 	.callback = backend_changed,
218*df660251SIan Campbell };
219*df660251SIan Campbell 
220*df660251SIan Campbell static int read_frontend_details(struct xenbus_device *xendev)
221*df660251SIan Campbell {
222*df660251SIan Campbell 	return xenbus_read_otherend_details(xendev, "frontend-id", "frontend");
223*df660251SIan Campbell }
224*df660251SIan Campbell 
225*df660251SIan Campbell //void xenbus_backend_suspend(int (*fn)(struct device *, void *))
226*df660251SIan Campbell //{
227*df660251SIan Campbell //	DPRINTK("");
228*df660251SIan Campbell //	bus_for_each_dev(&xenbus_backend.bus, NULL, NULL, fn);
229*df660251SIan Campbell //}
230*df660251SIan Campbell 
231*df660251SIan Campbell //void xenbus_backend_resume(int (*fn)(struct device *, void *))
232*df660251SIan Campbell //{
233*df660251SIan Campbell //	DPRINTK("");
234*df660251SIan Campbell //	bus_for_each_dev(&xenbus_backend.bus, NULL, NULL, fn);
235*df660251SIan Campbell //}
236*df660251SIan Campbell 
237*df660251SIan Campbell //int xenbus_for_each_backend(void *arg, int (*fn)(struct device *, void *))
238*df660251SIan Campbell //{
239*df660251SIan Campbell //	return bus_for_each_dev(&xenbus_backend.bus, NULL, arg, fn);
240*df660251SIan Campbell //}
241*df660251SIan Campbell //EXPORT_SYMBOL_GPL(xenbus_for_each_backend);
242*df660251SIan Campbell 
243*df660251SIan Campbell int xenbus_dev_is_online(struct xenbus_device *dev)
244*df660251SIan Campbell {
245*df660251SIan Campbell 	int rc, val;
246*df660251SIan Campbell 
247*df660251SIan Campbell 	rc = xenbus_scanf(XBT_NIL, dev->nodename, "online", "%d", &val);
248*df660251SIan Campbell 	if (rc != 1)
249*df660251SIan Campbell 		val = 0; /* no online node present */
250*df660251SIan Campbell 
251*df660251SIan Campbell 	return val;
252*df660251SIan Campbell }
253*df660251SIan Campbell EXPORT_SYMBOL_GPL(xenbus_dev_is_online);
254*df660251SIan Campbell 
255*df660251SIan Campbell int __xenbus_register_backend(struct xenbus_driver *drv,
256*df660251SIan Campbell 			      struct module *owner, const char *mod_name)
257*df660251SIan Campbell {
258*df660251SIan Campbell 	drv->read_otherend_details = read_frontend_details;
259*df660251SIan Campbell 
260*df660251SIan Campbell 	return xenbus_register_driver_common(drv, &xenbus_backend,
261*df660251SIan Campbell 					     owner, mod_name);
262*df660251SIan Campbell }
263*df660251SIan Campbell EXPORT_SYMBOL_GPL(__xenbus_register_backend);
264*df660251SIan Campbell 
265*df660251SIan Campbell static int backend_probe_and_watch(struct notifier_block *notifier,
266*df660251SIan Campbell 				   unsigned long event,
267*df660251SIan Campbell 				   void *data)
268*df660251SIan Campbell {
269*df660251SIan Campbell 	/* Enumerate devices in xenstore and watch for changes. */
270*df660251SIan Campbell 	xenbus_probe_devices(&xenbus_backend);
271*df660251SIan Campbell 	printk(KERN_CRIT "%s devices probed ok\n", __func__);
272*df660251SIan Campbell 	register_xenbus_watch(&be_watch);
273*df660251SIan Campbell 	printk(KERN_CRIT "%s watch add ok ok\n", __func__);
274*df660251SIan Campbell 	printk(KERN_CRIT "%s all done\n", __func__);
275*df660251SIan Campbell 	return NOTIFY_DONE;
276*df660251SIan Campbell }
277*df660251SIan Campbell 
278*df660251SIan Campbell static int __init xenbus_probe_backend_init(void)
279*df660251SIan Campbell {
280*df660251SIan Campbell 	static struct notifier_block xenstore_notifier = {
281*df660251SIan Campbell 		.notifier_call = backend_probe_and_watch
282*df660251SIan Campbell 	};
283*df660251SIan Campbell 	int err;
284*df660251SIan Campbell 
285*df660251SIan Campbell 	DPRINTK("");
286*df660251SIan Campbell 
287*df660251SIan Campbell 	/* Register ourselves with the kernel bus subsystem */
288*df660251SIan Campbell 	err = bus_register(&xenbus_backend.bus);
289*df660251SIan Campbell 	if (err) {
290*df660251SIan Campbell 		printk(KERN_CRIT "%s didn't register bus!\n", __func__);
291*df660251SIan Campbell 		return err;
292*df660251SIan Campbell 	}
293*df660251SIan Campbell 	printk(KERN_CRIT "%s bus registered ok\n", __func__);
294*df660251SIan Campbell 
295*df660251SIan Campbell 	register_xenstore_notifier(&xenstore_notifier);
296*df660251SIan Campbell 
297*df660251SIan Campbell 	return 0;
298*df660251SIan Campbell }
299*df660251SIan Campbell 
300*df660251SIan Campbell module_init(xenbus_probe_backend_init);
301