Merge to Fedora kernel-2.6.18-1.2224_FC5 patched with stable patch-2.6.18.1-vs2.0...
[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("%s", xenbus_strstate(frontend_state));
305
306         switch (frontend_state) {
307         case XenbusStateInitialising:
308                 if (dev->state == XenbusStateClosed) {
309                         printk("%s: %s: prepare for reconnect\n",
310                                __FUNCTION__, dev->nodename);
311                         xenbus_switch_state(dev, XenbusStateInitWait);
312                 }
313                 break;
314
315         case XenbusStateInitialised:
316         case XenbusStateConnected:
317                 /* Ensure we connect even when two watches fire in 
318                    close successsion and we miss the intermediate value 
319                    of frontend_state. */
320                 if (dev->state == XenbusStateConnected)
321                         break;
322
323                 err = connect_ring(be);
324                 if (err)
325                         break;
326                 update_blkif_status(be->blkif);
327                 break;
328
329         case XenbusStateClosing:
330                 blkif_disconnect(be->blkif);
331                 xenbus_switch_state(dev, XenbusStateClosing);
332                 break;
333
334         case XenbusStateClosed:
335                 xenbus_switch_state(dev, XenbusStateClosed);
336                 if (xenbus_dev_is_online(dev))
337                         break;
338                 /* fall through if not online */
339         case XenbusStateUnknown:
340                 device_unregister(&dev->dev);
341                 break;
342
343         default:
344                 xenbus_dev_fatal(dev, -EINVAL, "saw state %d at frontend",
345                                  frontend_state);
346                 break;
347         }
348 }
349
350
351 /* ** Connection ** */
352
353
354 /**
355  * Write the physical details regarding the block device to the store, and
356  * switch to Connected state.
357  */
358 static void connect(struct backend_info *be)
359 {
360         struct xenbus_transaction xbt;
361         int err;
362         struct xenbus_device *dev = be->dev;
363
364         DPRINTK("%s", dev->otherend);
365
366         /* Supply the information about the device the frontend needs */
367 again:
368         err = xenbus_transaction_start(&xbt);
369
370         if (err) {
371                 xenbus_dev_fatal(dev, err, "starting transaction");
372                 return;
373         }
374
375         err = xenbus_printf(xbt, dev->nodename, "sectors", "%lu",
376                             vbd_size(&be->blkif->vbd));
377         if (err) {
378                 xenbus_dev_fatal(dev, err, "writing %s/sectors",
379                                  dev->nodename);
380                 goto abort;
381         }
382
383         /* FIXME: use a typename instead */
384         err = xenbus_printf(xbt, dev->nodename, "info", "%u",
385                             vbd_info(&be->blkif->vbd));
386         if (err) {
387                 xenbus_dev_fatal(dev, err, "writing %s/info",
388                                  dev->nodename);
389                 goto abort;
390         }
391         err = xenbus_printf(xbt, dev->nodename, "sector-size", "%lu",
392                             vbd_secsize(&be->blkif->vbd));
393         if (err) {
394                 xenbus_dev_fatal(dev, err, "writing %s/sector-size",
395                                  dev->nodename);
396                 goto abort;
397         }
398
399         err = xenbus_transaction_end(xbt, 0);
400         if (err == -EAGAIN)
401                 goto again;
402         if (err)
403                 xenbus_dev_fatal(dev, err, "ending transaction");
404
405         err = xenbus_switch_state(dev, XenbusStateConnected);
406         if (err)
407                 xenbus_dev_fatal(dev, err, "switching to Connected state",
408                                  dev->nodename);
409
410         return;
411  abort:
412         xenbus_transaction_end(xbt, 1);
413 }
414
415
416 static int connect_ring(struct backend_info *be)
417 {
418         struct xenbus_device *dev = be->dev;
419         unsigned long ring_ref;
420         unsigned int evtchn;
421         int err;
422
423         DPRINTK("%s", dev->otherend);
424
425         err = xenbus_gather(XBT_NIL, dev->otherend, "ring-ref", "%lu", &ring_ref,
426                             "event-channel", "%u", &evtchn, NULL);
427         if (err) {
428                 xenbus_dev_fatal(dev, err,
429                                  "reading %s/ring-ref and event-channel",
430                                  dev->otherend);
431                 return err;
432         }
433
434         /* Map the shared frame, irq etc. */
435         err = blkif_map(be->blkif, ring_ref, evtchn);
436         if (err) {
437                 xenbus_dev_fatal(dev, err, "mapping ring-ref %lu port %u",
438                                  ring_ref, evtchn);
439                 return err;
440         }
441
442         return 0;
443 }
444
445
446 /* ** Driver Registration ** */
447
448
449 static struct xenbus_device_id blkback_ids[] = {
450         { "vbd" },
451         { "" }
452 };
453
454
455 static struct xenbus_driver blkback = {
456         .name = "vbd",
457         .owner = THIS_MODULE,
458         .ids = blkback_ids,
459         .probe = blkback_probe,
460         .remove = blkback_remove,
461         .otherend_changed = frontend_changed
462 };
463
464
465 void blkif_xenbus_init(void)
466 {
467         xenbus_register_backend(&blkback);
468 }