This commit was manufactured by cvs2svn to create branch 'vserver'.
[linux-2.6.git] / drivers / xen / blkback / xenbus.c
1 /*  Xenbus code for blkif backend
2     Copyright (C) 2005 Rusty Russell <rusty@rustcorp.com.au>
3     Copyright (C) 2005 XenSource Ltd
4
5     This program is free software; you can redistribute it and/or modify
6     it under the terms of the GNU General Public License as published by
7     the Free Software Foundation; either version 2 of the License, or
8     (at your option) any later version.
9
10     This program is distributed in the hope that it will be useful,
11     but WITHOUT ANY WARRANTY; without even the implied warranty of
12     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13     GNU General Public License for more details.
14
15     You should have received a copy of the GNU General Public License
16     along with this program; if not, write to the Free Software
17     Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
18 */
19
20 #include <stdarg.h>
21 #include <linux/module.h>
22 #include <linux/kthread.h>
23 #include <xen/xenbus.h>
24 #include "common.h"
25
26 #undef DPRINTK
27 #define DPRINTK(fmt, args...)                           \
28         pr_debug("blkback/xenbus (%s:%d) " fmt ".\n",   \
29                  __FUNCTION__, __LINE__, ##args)
30
31 struct backend_info
32 {
33         struct xenbus_device *dev;
34         blkif_t *blkif;
35         struct xenbus_watch backend_watch;
36         unsigned major;
37         unsigned minor;
38         char *mode;
39 };
40
41 static void connect(struct backend_info *);
42 static int connect_ring(struct backend_info *);
43 static void backend_changed(struct xenbus_watch *, const char **,
44                             unsigned int);
45
46 static void update_blkif_status(blkif_t *blkif)
47
48         int err;
49
50         /* Not ready to connect? */
51         if (!blkif->irq || !blkif->vbd.bdev)
52                 return;
53
54         /* Already connected? */
55         if (blkif->be->dev->state == XenbusStateConnected)
56                 return;
57
58         /* Attempt to connect: exit if we fail to. */
59         connect(blkif->be);
60         if (blkif->be->dev->state != XenbusStateConnected)
61                 return;
62
63         blkif->xenblkd = kthread_run(blkif_schedule, blkif,
64                                      "xvd %d %02x:%02x",
65                                      blkif->domid,
66                                      blkif->be->major, blkif->be->minor);
67         if (IS_ERR(blkif->xenblkd)) {
68                 err = PTR_ERR(blkif->xenblkd);
69                 blkif->xenblkd = NULL;
70                 xenbus_dev_error(blkif->be->dev, err, "start xenblkd");
71         }
72 }
73
74
75 /****************************************************************
76  *  sysfs interface for VBD I/O requests
77  */
78
79 #define VBD_SHOW(name, format, args...)                                 \
80         static ssize_t show_##name(struct device *_dev,                 \
81                                    struct device_attribute *attr,       \
82                                    char *buf)                           \
83         {                                                               \
84                 struct xenbus_device *dev = to_xenbus_device(_dev);     \
85                 struct backend_info *be = dev->dev.driver_data;         \
86                                                                         \
87                 return sprintf(buf, format, ##args);                    \
88         }                                                               \
89         DEVICE_ATTR(name, S_IRUGO, show_##name, NULL)
90
91 VBD_SHOW(oo_req, "%d\n", be->blkif->st_oo_req);
92 VBD_SHOW(rd_req, "%d\n", be->blkif->st_rd_req);
93 VBD_SHOW(wr_req, "%d\n", be->blkif->st_wr_req);
94
95 static struct attribute *vbdstat_attrs[] = {
96         &dev_attr_oo_req.attr,
97         &dev_attr_rd_req.attr,
98         &dev_attr_wr_req.attr,
99         NULL
100 };
101
102 static struct attribute_group vbdstat_group = {
103         .name = "statistics",
104         .attrs = vbdstat_attrs,
105 };
106
107 VBD_SHOW(physical_device, "%x:%x\n", be->major, be->minor);
108 VBD_SHOW(mode, "%s\n", be->mode);
109
110 int xenvbd_sysfs_addif(struct xenbus_device *dev)
111 {
112         int error;
113         
114         error = device_create_file(&dev->dev, &dev_attr_physical_device);
115         if (error)
116                 goto fail1;
117
118         error = device_create_file(&dev->dev, &dev_attr_mode);
119         if (error)
120                 goto fail2;
121
122         error = sysfs_create_group(&dev->dev.kobj, &vbdstat_group);
123         if (error)
124                 goto fail3;
125
126         return 0;
127
128 fail3:  sysfs_remove_group(&dev->dev.kobj, &vbdstat_group);
129 fail2:  device_remove_file(&dev->dev, &dev_attr_mode);
130 fail1:  device_remove_file(&dev->dev, &dev_attr_physical_device);
131         return error;
132 }
133
134 void xenvbd_sysfs_delif(struct xenbus_device *dev)
135 {
136         sysfs_remove_group(&dev->dev.kobj, &vbdstat_group);
137         device_remove_file(&dev->dev, &dev_attr_mode);
138         device_remove_file(&dev->dev, &dev_attr_physical_device);
139 }
140
141 static int blkback_remove(struct xenbus_device *dev)
142 {
143         struct backend_info *be = dev->dev.driver_data;
144
145         DPRINTK("");
146
147         if (be->backend_watch.node) {
148                 unregister_xenbus_watch(&be->backend_watch);
149                 kfree(be->backend_watch.node);
150                 be->backend_watch.node = NULL;
151         }
152
153         if (be->blkif) {
154                 blkif_disconnect(be->blkif);
155                 vbd_free(&be->blkif->vbd);
156                 blkif_free(be->blkif);
157                 be->blkif = NULL;
158         }
159
160         if (be->major || be->minor)
161                 xenvbd_sysfs_delif(dev);
162
163         kfree(be);
164         dev->dev.driver_data = NULL;
165         return 0;
166 }
167
168
169 /**
170  * Entry point to this code when a new device is created.  Allocate the basic
171  * structures, and watch the store waiting for the hotplug scripts to tell us
172  * the device's physical major and minor numbers.  Switch to InitWait.
173  */
174 static int blkback_probe(struct xenbus_device *dev,
175                          const struct xenbus_device_id *id)
176 {
177         int err;
178         struct backend_info *be = kzalloc(sizeof(struct backend_info),
179                                           GFP_KERNEL);
180         if (!be) {
181                 xenbus_dev_fatal(dev, -ENOMEM,
182                                  "allocating backend structure");
183                 return -ENOMEM;
184         }
185         be->dev = dev;
186         dev->dev.driver_data = be;
187
188         be->blkif = blkif_alloc(dev->otherend_id);
189         if (IS_ERR(be->blkif)) {
190                 err = PTR_ERR(be->blkif);
191                 be->blkif = NULL;
192                 xenbus_dev_fatal(dev, err, "creating block interface");
193                 goto fail;
194         }
195
196         /* setup back pointer */
197         be->blkif->be = be; 
198
199         err = xenbus_watch_path2(dev, dev->nodename, "physical-device",
200                                  &be->backend_watch, backend_changed);
201         if (err)
202                 goto fail;
203
204         err = xenbus_switch_state(dev, XenbusStateInitWait);
205         if (err)
206                 goto fail;
207
208         return 0;
209
210 fail:
211         DPRINTK("failed");
212         blkback_remove(dev);
213         return err;
214 }
215
216
217 /**
218  * Callback received when the hotplug scripts have placed the physical-device
219  * node.  Read it and the mode node, and create a vbd.  If the frontend is
220  * ready, connect.
221  */
222 static void backend_changed(struct xenbus_watch *watch,
223                             const char **vec, unsigned int len)
224 {
225         int err;
226         unsigned major;
227         unsigned minor;
228         struct backend_info *be
229                 = container_of(watch, struct backend_info, backend_watch);
230         struct xenbus_device *dev = be->dev;
231
232         DPRINTK("");
233
234         err = xenbus_scanf(XBT_NIL, dev->nodename, "physical-device", "%x:%x",
235                            &major, &minor);
236         if (XENBUS_EXIST_ERR(err)) {
237                 /* Since this watch will fire once immediately after it is
238                    registered, we expect this.  Ignore it, and wait for the
239                    hotplug scripts. */
240                 return;
241         }
242         if (err != 2) {
243                 xenbus_dev_fatal(dev, err, "reading physical-device");
244                 return;
245         }
246
247         if ((be->major || be->minor) &&
248             ((be->major != major) || (be->minor != minor))) {
249                 printk(KERN_WARNING
250                        "blkback: changing physical device (from %x:%x to "
251                        "%x:%x) not supported.\n", be->major, be->minor,
252                        major, minor);
253                 return;
254         }
255
256         be->mode = xenbus_read(XBT_NIL, dev->nodename, "mode", NULL);
257         if (IS_ERR(be->mode)) {
258                 err = PTR_ERR(be->mode);
259                 be->mode = NULL;
260                 xenbus_dev_fatal(dev, err, "reading mode");
261                 return;
262         }
263
264         if (be->major == 0 && be->minor == 0) {
265                 /* Front end dir is a number, which is used as the handle. */
266
267                 char *p = strrchr(dev->otherend, '/') + 1;
268                 long handle = simple_strtoul(p, NULL, 0);
269
270                 be->major = major;
271                 be->minor = minor;
272
273                 err = vbd_create(be->blkif, handle, major, minor,
274                                  (NULL == strchr(be->mode, 'w')));
275                 if (err) {
276                         be->major = be->minor = 0;
277                         xenbus_dev_fatal(dev, err, "creating vbd structure");
278                         return;
279                 }
280
281                 err = xenvbd_sysfs_addif(dev);
282                 if (err) {
283                         vbd_free(&be->blkif->vbd);
284                         be->major = be->minor = 0;
285                         xenbus_dev_fatal(dev, err, "creating sysfs entries");
286                         return;
287                 }
288
289                 /* We're potentially connected now */
290                 update_blkif_status(be->blkif); 
291         }
292 }
293
294
295 /**
296  * Callback received when the frontend's state changes.
297  */
298 static void frontend_changed(struct xenbus_device *dev,
299                              enum xenbus_state frontend_state)
300 {
301         struct backend_info *be = dev->dev.driver_data;
302         int err;
303
304         DPRINTK("");
305
306         switch (frontend_state) {
307         case XenbusStateInitialising:
308                 break;
309
310         case XenbusStateInitialised:
311         case XenbusStateConnected:
312                 /* Ensure we connect even when two watches fire in 
313                    close successsion and we miss the intermediate value 
314                    of frontend_state. */
315                 if (dev->state == XenbusStateConnected)
316                         break;
317
318                 err = connect_ring(be);
319                 if (err)
320                         break;
321                 update_blkif_status(be->blkif);
322                 break;
323
324         case XenbusStateClosing:
325                 blkif_disconnect(be->blkif);
326                 xenbus_switch_state(dev, XenbusStateClosing);
327                 break;
328
329         case XenbusStateClosed:
330                 device_unregister(&dev->dev);
331                 break;
332
333         case XenbusStateUnknown:
334         case XenbusStateInitWait:
335         default:
336                 xenbus_dev_fatal(dev, -EINVAL, "saw state %d at frontend",
337                                  frontend_state);
338                 break;
339         }
340 }
341
342
343 /* ** Connection ** */
344
345
346 /**
347  * Write the physical details regarding the block device to the store, and
348  * switch to Connected state.
349  */
350 static void connect(struct backend_info *be)
351 {
352         struct xenbus_transaction xbt;
353         int err;
354         struct xenbus_device *dev = be->dev;
355
356         DPRINTK("%s", dev->otherend);
357
358         /* Supply the information about the device the frontend needs */
359 again:
360         err = xenbus_transaction_start(&xbt);
361
362         if (err) {
363                 xenbus_dev_fatal(dev, err, "starting transaction");
364                 return;
365         }
366
367         err = xenbus_printf(xbt, dev->nodename, "sectors", "%lu",
368                             vbd_size(&be->blkif->vbd));
369         if (err) {
370                 xenbus_dev_fatal(dev, err, "writing %s/sectors",
371                                  dev->nodename);
372                 goto abort;
373         }
374
375         /* FIXME: use a typename instead */
376         err = xenbus_printf(xbt, dev->nodename, "info", "%u",
377                             vbd_info(&be->blkif->vbd));
378         if (err) {
379                 xenbus_dev_fatal(dev, err, "writing %s/info",
380                                  dev->nodename);
381                 goto abort;
382         }
383         err = xenbus_printf(xbt, dev->nodename, "sector-size", "%lu",
384                             vbd_secsize(&be->blkif->vbd));
385         if (err) {
386                 xenbus_dev_fatal(dev, err, "writing %s/sector-size",
387                                  dev->nodename);
388                 goto abort;
389         }
390
391         err = xenbus_transaction_end(xbt, 0);
392         if (err == -EAGAIN)
393                 goto again;
394         if (err)
395                 xenbus_dev_fatal(dev, err, "ending transaction");
396
397         err = xenbus_switch_state(dev, XenbusStateConnected);
398         if (err)
399                 xenbus_dev_fatal(dev, err, "switching to Connected state",
400                                  dev->nodename);
401
402         return;
403  abort:
404         xenbus_transaction_end(xbt, 1);
405 }
406
407
408 static int connect_ring(struct backend_info *be)
409 {
410         struct xenbus_device *dev = be->dev;
411         unsigned long ring_ref;
412         unsigned int evtchn;
413         int err;
414
415         DPRINTK("%s", dev->otherend);
416
417         err = xenbus_gather(XBT_NIL, dev->otherend, "ring-ref", "%lu", &ring_ref,
418                             "event-channel", "%u", &evtchn, NULL);
419         if (err) {
420                 xenbus_dev_fatal(dev, err,
421                                  "reading %s/ring-ref and event-channel",
422                                  dev->otherend);
423                 return err;
424         }
425
426         /* Map the shared frame, irq etc. */
427         err = blkif_map(be->blkif, ring_ref, evtchn);
428         if (err) {
429                 xenbus_dev_fatal(dev, err, "mapping ring-ref %lu port %u",
430                                  ring_ref, evtchn);
431                 return err;
432         }
433
434         return 0;
435 }
436
437
438 /* ** Driver Registration ** */
439
440
441 static struct xenbus_device_id blkback_ids[] = {
442         { "vbd" },
443         { "" }
444 };
445
446
447 static struct xenbus_driver blkback = {
448         .name = "vbd",
449         .owner = THIS_MODULE,
450         .ids = blkback_ids,
451         .probe = blkback_probe,
452         .remove = blkback_remove,
453         .otherend_changed = frontend_changed
454 };
455
456
457 void blkif_xenbus_init(void)
458 {
459         xenbus_register_backend(&blkback);
460 }