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