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 / tpmback / xenbus.c
1 /*  Xenbus code for tpmif backend
2     Copyright (C) 2005 IBM Corporation
3     Copyright (C) 2005 Rusty Russell <rusty@rustcorp.com.au>
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 #include <stdarg.h>
20 #include <linux/module.h>
21 #include <xen/xenbus.h>
22 #include "common.h"
23
24 struct backend_info
25 {
26         struct xenbus_device *dev;
27
28         /* our communications channel */
29         tpmif_t *tpmif;
30
31         long int frontend_id;
32         long int instance; // instance of TPM
33         u8 is_instance_set;// whether instance number has been set
34
35         /* watch front end for changes */
36         struct xenbus_watch backend_watch;
37 };
38
39 static void maybe_connect(struct backend_info *be);
40 static void connect(struct backend_info *be);
41 static int connect_ring(struct backend_info *be);
42 static void backend_changed(struct xenbus_watch *watch,
43                             const char **vec, unsigned int len);
44 static void frontend_changed(struct xenbus_device *dev,
45                              enum xenbus_state frontend_state);
46
47 long int tpmback_get_instance(struct backend_info *bi)
48 {
49         long int res = -1;
50         if (bi && bi->is_instance_set)
51                 res = bi->instance;
52         return res;
53 }
54
55 static int tpmback_remove(struct xenbus_device *dev)
56 {
57         struct backend_info *be = dev->dev.driver_data;
58
59         if (!be) return 0;
60
61         if (be->backend_watch.node) {
62                 unregister_xenbus_watch(&be->backend_watch);
63                 kfree(be->backend_watch.node);
64                 be->backend_watch.node = NULL;
65         }
66         if (be->tpmif) {
67                 be->tpmif->bi = NULL;
68                 vtpm_release_packets(be->tpmif, 0);
69                 tpmif_put(be->tpmif);
70                 be->tpmif = NULL;
71         }
72         kfree(be);
73         dev->dev.driver_data = NULL;
74         return 0;
75 }
76
77 static int tpmback_probe(struct xenbus_device *dev,
78                          const struct xenbus_device_id *id)
79 {
80         int err;
81         struct backend_info *be = kzalloc(sizeof(struct backend_info),
82                                           GFP_KERNEL);
83
84         if (!be) {
85                 xenbus_dev_fatal(dev, -ENOMEM,
86                                  "allocating backend structure");
87                 return -ENOMEM;
88         }
89
90         be->is_instance_set = 0;
91         be->dev = dev;
92         dev->dev.driver_data = be;
93
94         err = xenbus_watch_path2(dev, dev->nodename,
95                                  "instance", &be->backend_watch,
96                                  backend_changed);
97         if (err) {
98                 goto fail;
99         }
100
101         err = xenbus_switch_state(dev, XenbusStateInitWait);
102         if (err) {
103                 goto fail;
104         }
105         return 0;
106 fail:
107         tpmback_remove(dev);
108         return err;
109 }
110
111
112 static void backend_changed(struct xenbus_watch *watch,
113                             const char **vec, unsigned int len)
114 {
115         int err;
116         long instance;
117         struct backend_info *be
118                 = container_of(watch, struct backend_info, backend_watch);
119         struct xenbus_device *dev = be->dev;
120
121         err = xenbus_scanf(XBT_NIL, dev->nodename,
122                            "instance","%li", &instance);
123         if (XENBUS_EXIST_ERR(err)) {
124                 return;
125         }
126
127         if (err != 1) {
128                 xenbus_dev_fatal(dev, err, "reading instance");
129                 return;
130         }
131
132         if (be->is_instance_set == 0) {
133                 be->instance = instance;
134                 be->is_instance_set = 1;
135         }
136 }
137
138
139 static void frontend_changed(struct xenbus_device *dev,
140                              enum xenbus_state frontend_state)
141 {
142         struct backend_info *be = dev->dev.driver_data;
143         int err;
144
145         switch (frontend_state) {
146         case XenbusStateInitialising:
147         case XenbusStateInitialised:
148                 break;
149
150         case XenbusStateConnected:
151                 err = connect_ring(be);
152                 if (err) {
153                         return;
154                 }
155                 maybe_connect(be);
156                 break;
157
158         case XenbusStateClosing:
159                 be->instance = -1;
160                 break;
161
162         case XenbusStateUnknown:
163         case XenbusStateClosed:
164                 device_unregister(&be->dev->dev);
165                 tpmback_remove(dev);
166                 break;
167
168         default:
169                 xenbus_dev_fatal(dev, -EINVAL,
170                                  "saw state %d at frontend",
171                                  frontend_state);
172                 break;
173         }
174 }
175
176
177
178 static void maybe_connect(struct backend_info *be)
179 {
180         if (be->tpmif == NULL || be->tpmif->status == CONNECTED)
181                 return;
182
183         connect(be);
184 }
185
186
187 static void connect(struct backend_info *be)
188 {
189         struct xenbus_transaction xbt;
190         int err;
191         struct xenbus_device *dev = be->dev;
192         unsigned long ready = 1;
193
194 again:
195         err = xenbus_transaction_start(&xbt);
196         if (err) {
197                 xenbus_dev_fatal(be->dev, err, "starting transaction");
198                 return;
199         }
200
201         err = xenbus_printf(xbt, be->dev->nodename,
202                             "ready", "%lu", ready);
203         if (err) {
204                 xenbus_dev_fatal(be->dev, err, "writing 'ready'");
205                 goto abort;
206         }
207
208         err = xenbus_transaction_end(xbt, 0);
209         if (err == -EAGAIN)
210                 goto again;
211         if (err)
212                 xenbus_dev_fatal(be->dev, err, "end of transaction");
213
214         err = xenbus_switch_state(dev, XenbusStateConnected);
215         if (!err)
216                 be->tpmif->status = CONNECTED;
217         return;
218 abort:
219         xenbus_transaction_end(xbt, 1);
220 }
221
222
223 static int connect_ring(struct backend_info *be)
224 {
225         struct xenbus_device *dev = be->dev;
226         unsigned long ring_ref;
227         unsigned int evtchn;
228         int err;
229
230         err = xenbus_gather(XBT_NIL, dev->otherend,
231                             "ring-ref", "%lu", &ring_ref,
232                             "event-channel", "%u", &evtchn, NULL);
233         if (err) {
234                 xenbus_dev_error(dev, err,
235                                  "reading %s/ring-ref and event-channel",
236                                  dev->otherend);
237                 return err;
238         }
239
240         if (!be->tpmif) {
241                 be->tpmif = tpmif_find(dev->otherend_id, be);
242                 if (IS_ERR(be->tpmif)) {
243                         err = PTR_ERR(be->tpmif);
244                         be->tpmif = NULL;
245                         xenbus_dev_fatal(dev,err,"creating vtpm interface");
246                         return err;
247                 }
248         }
249
250         if (be->tpmif != NULL) {
251                 err = tpmif_map(be->tpmif, ring_ref, evtchn);
252                 if (err) {
253                         xenbus_dev_error(dev, err,
254                                          "mapping shared-frame %lu port %u",
255                                          ring_ref, evtchn);
256                         return err;
257                 }
258         }
259         return 0;
260 }
261
262
263 static struct xenbus_device_id tpmback_ids[] = {
264         { "vtpm" },
265         { "" }
266 };
267
268
269 static struct xenbus_driver tpmback = {
270         .name = "vtpm",
271         .owner = THIS_MODULE,
272         .ids = tpmback_ids,
273         .probe = tpmback_probe,
274         .remove = tpmback_remove,
275         .otherend_changed = frontend_changed,
276 };
277
278
279 void tpmif_xenbus_init(void)
280 {
281         xenbus_register_backend(&tpmback);
282 }
283
284 void tpmif_xenbus_exit(void)
285 {
286         xenbus_unregister_driver(&tpmback);
287 }