1*b95803dcSjdolecek /* $NetBSD: xenbus_client.c,v 1.17 2020/04/07 15:16:52 jdolecek Exp $ */
2ed3fe49dSbouyer /******************************************************************************
3ed3fe49dSbouyer * Client-facing interface for the Xenbus driver. In other words, the
4ed3fe49dSbouyer * interface between the Xenbus and the device-specific code, be it the
5ed3fe49dSbouyer * frontend or the backend of that driver.
6ed3fe49dSbouyer *
7ed3fe49dSbouyer * Copyright (C) 2005 XenSource Ltd
8ed3fe49dSbouyer *
9ed3fe49dSbouyer * This file may be distributed separately from the Linux kernel, or
10ed3fe49dSbouyer * incorporated into other software packages, subject to the following license:
11ed3fe49dSbouyer *
12ed3fe49dSbouyer * Permission is hereby granted, free of charge, to any person obtaining a copy
13ed3fe49dSbouyer * of this source file (the "Software"), to deal in the Software without
14ed3fe49dSbouyer * restriction, including without limitation the rights to use, copy, modify,
15ed3fe49dSbouyer * merge, publish, distribute, sublicense, and/or sell copies of the Software,
16ed3fe49dSbouyer * and to permit persons to whom the Software is furnished to do so, subject to
17ed3fe49dSbouyer * the following conditions:
18ed3fe49dSbouyer *
19ed3fe49dSbouyer * The above copyright notice and this permission notice shall be included in
20ed3fe49dSbouyer * all copies or substantial portions of the Software.
21ed3fe49dSbouyer *
22ed3fe49dSbouyer * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
23ed3fe49dSbouyer * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
24ed3fe49dSbouyer * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
25ed3fe49dSbouyer * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
26ed3fe49dSbouyer * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
27ed3fe49dSbouyer * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
28ed3fe49dSbouyer * IN THE SOFTWARE.
29ed3fe49dSbouyer */
30ed3fe49dSbouyer
3116046408Sbouyer #include <sys/cdefs.h>
32*b95803dcSjdolecek __KERNEL_RCSID(0, "$NetBSD: xenbus_client.c,v 1.17 2020/04/07 15:16:52 jdolecek Exp $");
33ed3fe49dSbouyer
34ed3fe49dSbouyer #if 0
35ed3fe49dSbouyer #define DPRINTK(fmt, args...) \
369b2b412cSperry printk("xenbus_client (%s:%d) " fmt ".\n", __func__, __LINE__, ##args)
37ed3fe49dSbouyer #else
38ed3fe49dSbouyer #define DPRINTK(fmt, args...) ((void)0)
39ed3fe49dSbouyer #endif
40ed3fe49dSbouyer
4116046408Sbouyer #include <sys/types.h>
4216046408Sbouyer #include <sys/null.h>
4316046408Sbouyer #include <sys/errno.h>
44418f6d13Sjdolecek #include <sys/kmem.h>
4516046408Sbouyer #include <sys/systm.h>
46ed3fe49dSbouyer
474e541343Sbouyer #include <xen/xen.h>
484e541343Sbouyer #include <xen/hypervisor.h>
494e541343Sbouyer #include <xen/evtchn.h>
504e541343Sbouyer #include <xen/xenbus.h>
514e541343Sbouyer #include <xen/granttables.h>
52ed3fe49dSbouyer
5316046408Sbouyer int
xenbus_watch_path2(struct xenbus_device * dev,const char * path,const char * path2,struct xenbus_watch * watch,void (* callback)(struct xenbus_watch *,const char **,unsigned int))5416046408Sbouyer xenbus_watch_path2(struct xenbus_device *dev, const char *path,
55ed3fe49dSbouyer const char *path2, struct xenbus_watch *watch,
56ed3fe49dSbouyer void (*callback)(struct xenbus_watch *,
57ed3fe49dSbouyer const char **, unsigned int))
58ed3fe49dSbouyer {
59ed3fe49dSbouyer int err;
60aceceafcSbouyer char *state;
61aceceafcSbouyer
62aceceafcSbouyer DPRINTK("xenbus_watch_path2 path %s path2 %s\n", path, path2);
63418f6d13Sjdolecek
64418f6d13Sjdolecek watch->node_sz = strlen(path) + 1 + strlen(path2) + 1;
65418f6d13Sjdolecek state = kmem_alloc(watch->node_sz, KM_SLEEP);
66ed3fe49dSbouyer strcpy(state, path);
67ed3fe49dSbouyer strcat(state, "/");
68ed3fe49dSbouyer strcat(state, path2);
69ed3fe49dSbouyer
70418f6d13Sjdolecek watch->node = state;
71418f6d13Sjdolecek watch->xbw_callback = callback;
72418f6d13Sjdolecek
73418f6d13Sjdolecek err = register_xenbus_watch(watch);
74ed3fe49dSbouyer
75ed3fe49dSbouyer if (err) {
76418f6d13Sjdolecek watch->node = NULL;
77418f6d13Sjdolecek watch->node_sz = 0;
78418f6d13Sjdolecek watch->xbw_callback = NULL;
79418f6d13Sjdolecek xenbus_dev_fatal(dev, err, "adding watch on %s", state);
80418f6d13Sjdolecek kmem_free(state, watch->node_sz);
81ed3fe49dSbouyer }
82ed3fe49dSbouyer return err;
83ed3fe49dSbouyer }
84ed3fe49dSbouyer
85418f6d13Sjdolecek void
xenbus_unwatch_path(struct xenbus_watch * watch)86418f6d13Sjdolecek xenbus_unwatch_path(struct xenbus_watch *watch)
87418f6d13Sjdolecek {
88418f6d13Sjdolecek if (watch->node != NULL) {
89418f6d13Sjdolecek unregister_xenbus_watch(watch);
90418f6d13Sjdolecek kmem_free(watch->node, watch->node_sz);
91418f6d13Sjdolecek watch->node = NULL;
92418f6d13Sjdolecek }
93418f6d13Sjdolecek }
94ed3fe49dSbouyer
9516046408Sbouyer int
xenbus_switch_state(struct xenbus_device * dev,struct xenbus_transaction * xbt,XenbusState state)9616046408Sbouyer xenbus_switch_state(struct xenbus_device *dev,
97ed3fe49dSbouyer struct xenbus_transaction *xbt,
98ed3fe49dSbouyer XenbusState state)
99ed3fe49dSbouyer {
100ed3fe49dSbouyer /* We check whether the state is currently set to the given value, and
101ed3fe49dSbouyer if not, then the state is set. We don't want to unconditionally
102ed3fe49dSbouyer write the given state, because we don't want to fire watches
103ed3fe49dSbouyer unnecessarily. Furthermore, if the node has gone, we don't write
104ed3fe49dSbouyer to it, as the device will be tearing down, and we don't want to
105ed3fe49dSbouyer resurrect that directory.
106ed3fe49dSbouyer */
107ed3fe49dSbouyer
10814e4157fSbouyer u_long current_state;
109ed3fe49dSbouyer
1102613e19eSbouyer int err = xenbus_read_ul(xbt, dev->xbusd_path, "state",
1112613e19eSbouyer ¤t_state, 10);
11214e4157fSbouyer if (err)
11314e4157fSbouyer return 0;
11414e4157fSbouyer
11514e4157fSbouyer if ((XenbusState)current_state == state)
116ed3fe49dSbouyer return 0;
117ed3fe49dSbouyer
11816046408Sbouyer err = xenbus_printf(xbt, dev->xbusd_path, "state", "%d", state);
119ed3fe49dSbouyer if (err) {
120ed3fe49dSbouyer xenbus_dev_fatal(dev, err, "writing new state");
121ed3fe49dSbouyer return err;
122ed3fe49dSbouyer }
123ed3fe49dSbouyer return 0;
124ed3fe49dSbouyer }
125ed3fe49dSbouyer
126ed3fe49dSbouyer /**
127ed3fe49dSbouyer * Return the path to the error node for the given device, or NULL on failure.
128ed3fe49dSbouyer * If the value returned is non-NULL, then it is the caller's to kfree.
129ed3fe49dSbouyer */
13016046408Sbouyer static char *
error_path(struct xenbus_device * dev,size_t * len)131*b95803dcSjdolecek error_path(struct xenbus_device *dev, size_t *len)
132ed3fe49dSbouyer {
133*b95803dcSjdolecek *len = strlen("error/") + strlen(dev->xbusd_path) + 1;
134*b95803dcSjdolecek char *path_buffer = kmem_alloc(*len, KM_NOSLEEP);
135*b95803dcSjdolecek if (path_buffer == NULL)
136ed3fe49dSbouyer return NULL;
137ed3fe49dSbouyer
138ed3fe49dSbouyer strcpy(path_buffer, "error/");
13916046408Sbouyer strcpy(path_buffer + strlen("error/"), dev->xbusd_path);
140ed3fe49dSbouyer
141ed3fe49dSbouyer return path_buffer;
142ed3fe49dSbouyer }
143ed3fe49dSbouyer
144ed3fe49dSbouyer
14516046408Sbouyer static void
_dev_error(struct xenbus_device * dev,int err,const char * fmt,va_list ap)14616046408Sbouyer _dev_error(struct xenbus_device *dev, int err, const char *fmt,
147ed3fe49dSbouyer va_list ap)
148ed3fe49dSbouyer {
149bb4d9fb0Sbouyer int ret __diagused;
150ed3fe49dSbouyer unsigned int len;
151ed3fe49dSbouyer char *printf_buffer = NULL, *path_buffer = NULL;
152*b95803dcSjdolecek size_t path_buffer_sz = 0;
153ed3fe49dSbouyer
154ed3fe49dSbouyer #define PRINTF_BUFFER_SIZE 4096
155*b95803dcSjdolecek printf_buffer = kmem_alloc(PRINTF_BUFFER_SIZE, KM_NOSLEEP);
156ed3fe49dSbouyer if (printf_buffer == NULL)
157ed3fe49dSbouyer goto fail;
158ed3fe49dSbouyer
15918c8862fScegger len = snprintf(printf_buffer, PRINTF_BUFFER_SIZE, "%i ", -err);
160e93b33c9Schristos KASSERT(len < PRINTF_BUFFER_SIZE);
161ed3fe49dSbouyer ret = vsnprintf(printf_buffer+len, PRINTF_BUFFER_SIZE-len, fmt, ap);
16216046408Sbouyer KASSERT(len + ret < PRINTF_BUFFER_SIZE);
16316046408Sbouyer dev->xbusd_has_error = 1;
164ed3fe49dSbouyer
165*b95803dcSjdolecek path_buffer = error_path(dev, &path_buffer_sz);
166ed3fe49dSbouyer if (path_buffer == NULL) {
167ed3fe49dSbouyer printk("xenbus: failed to write error node for %s (%s)\n",
16816046408Sbouyer dev->xbusd_path, printf_buffer);
169ed3fe49dSbouyer goto fail;
170ed3fe49dSbouyer }
171ed3fe49dSbouyer
172ed3fe49dSbouyer if (xenbus_write(NULL, path_buffer, "error", printf_buffer) != 0) {
173ed3fe49dSbouyer printk("xenbus: failed to write error node for %s (%s)\n",
17416046408Sbouyer dev->xbusd_path, printf_buffer);
175ed3fe49dSbouyer goto fail;
176ed3fe49dSbouyer }
177ed3fe49dSbouyer
178ed3fe49dSbouyer fail:
179ed3fe49dSbouyer if (printf_buffer)
180*b95803dcSjdolecek kmem_free(printf_buffer, PRINTF_BUFFER_SIZE);
181ed3fe49dSbouyer if (path_buffer)
182*b95803dcSjdolecek kmem_free(path_buffer, path_buffer_sz);
183ed3fe49dSbouyer }
184ed3fe49dSbouyer
185ed3fe49dSbouyer
18616046408Sbouyer void
xenbus_dev_error(struct xenbus_device * dev,int err,const char * fmt,...)18716046408Sbouyer xenbus_dev_error(struct xenbus_device *dev, int err, const char *fmt,
188ed3fe49dSbouyer ...)
189ed3fe49dSbouyer {
190ed3fe49dSbouyer va_list ap;
191ed3fe49dSbouyer
192ed3fe49dSbouyer va_start(ap, fmt);
193ed3fe49dSbouyer _dev_error(dev, err, fmt, ap);
194ed3fe49dSbouyer va_end(ap);
195ed3fe49dSbouyer }
196ed3fe49dSbouyer
197ed3fe49dSbouyer
19816046408Sbouyer void
xenbus_dev_fatal(struct xenbus_device * dev,int err,const char * fmt,...)19916046408Sbouyer xenbus_dev_fatal(struct xenbus_device *dev, int err, const char *fmt,
200ed3fe49dSbouyer ...)
201ed3fe49dSbouyer {
202ed3fe49dSbouyer va_list ap;
203ed3fe49dSbouyer
204ed3fe49dSbouyer va_start(ap, fmt);
205ed3fe49dSbouyer _dev_error(dev, err, fmt, ap);
206ed3fe49dSbouyer va_end(ap);
207ed3fe49dSbouyer
208ed3fe49dSbouyer xenbus_switch_state(dev, NULL, XenbusStateClosing);
209ed3fe49dSbouyer }
210ed3fe49dSbouyer
211ed3fe49dSbouyer
21216046408Sbouyer int
xenbus_grant_ring(struct xenbus_device * dev,paddr_t ring_pa,grant_ref_t * entryp)21316046408Sbouyer xenbus_grant_ring(struct xenbus_device *dev, paddr_t ring_pa,
21416046408Sbouyer grant_ref_t *entryp)
215ed3fe49dSbouyer {
21616046408Sbouyer int err = xengnt_grant_access(dev->xbusd_otherend_id, ring_pa,
21716046408Sbouyer 0, entryp);
21816046408Sbouyer if (err != 0)
219ed3fe49dSbouyer xenbus_dev_fatal(dev, err, "granting access to ring page");
220ed3fe49dSbouyer return err;
221ed3fe49dSbouyer }
222ed3fe49dSbouyer
223ed3fe49dSbouyer
22416046408Sbouyer int
xenbus_alloc_evtchn(struct xenbus_device * dev,int * port)22516046408Sbouyer xenbus_alloc_evtchn(struct xenbus_device *dev, int *port)
226ed3fe49dSbouyer {
227ed3fe49dSbouyer evtchn_op_t op = {
228ed3fe49dSbouyer .cmd = EVTCHNOP_alloc_unbound,
2290f256b9dStron .u.alloc_unbound = {
2300f256b9dStron .dom = DOMID_SELF,
2310f256b9dStron .remote_dom = dev->xbusd_otherend_id,
2320f256b9dStron .port = 0
2330f256b9dStron }
2340f256b9dStron };
235ed3fe49dSbouyer
236ed3fe49dSbouyer int err = HYPERVISOR_event_channel_op(&op);
237ed3fe49dSbouyer if (err)
238ed3fe49dSbouyer xenbus_dev_fatal(dev, err, "allocating event channel");
239ed3fe49dSbouyer else
240ed3fe49dSbouyer *port = op.u.alloc_unbound.port;
241ed3fe49dSbouyer return err;
242ed3fe49dSbouyer }
243ed3fe49dSbouyer
244ed3fe49dSbouyer
24516046408Sbouyer XenbusState
xenbus_read_driver_state(const char * path)24616046408Sbouyer xenbus_read_driver_state(const char *path)
247ed3fe49dSbouyer {
24814e4157fSbouyer u_long result;
249ed3fe49dSbouyer
2502613e19eSbouyer int err = xenbus_read_ul(NULL, path, "state", &result, 10);
251ed3fe49dSbouyer if (err)
252ed3fe49dSbouyer result = XenbusStateClosed;
253ed3fe49dSbouyer
254ed3fe49dSbouyer return result;
255ed3fe49dSbouyer }
256ed3fe49dSbouyer
257ed3fe49dSbouyer
258ed3fe49dSbouyer /*
259ed3fe49dSbouyer * Local variables:
260ed3fe49dSbouyer * c-file-style: "linux"
261ed3fe49dSbouyer * indent-tabs-mode: t
262ed3fe49dSbouyer * c-indent-level: 8
263ed3fe49dSbouyer * c-basic-offset: 8
264ed3fe49dSbouyer * tab-width: 8
265ed3fe49dSbouyer * End:
266ed3fe49dSbouyer */
267