Update to 3.4-final.
[linux-flexiantxendom0-3.2.10.git] / drivers / xen / scsiback / xenbus.c
1 /*
2  * Xen SCSI backend driver
3  *
4  * Copyright (c) 2008, FUJITSU Limited
5  *
6  * Based on the blkback driver code.
7  *
8  * This program is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU General Public License version 2
10  * as published by the Free Software Foundation; or, when distributed
11  * separately from the Linux kernel or incorporated into other
12  * software packages, subject to the following license:
13  * 
14  * Permission is hereby granted, free of charge, to any person obtaining a copy
15  * of this source file (the "Software"), to deal in the Software without
16  * restriction, including without limitation the rights to use, copy, modify,
17  * merge, publish, distribute, sublicense, and/or sell copies of the Software,
18  * and to permit persons to whom the Software is furnished to do so, subject to
19  * the following conditions:
20  * 
21  * The above copyright notice and this permission notice shall be included in
22  * all copies or substantial portions of the Software.
23  * 
24  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
25  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
26  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
27  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
28  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
29  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
30  * IN THE SOFTWARE.
31  */
32
33 #include <stdarg.h>
34 #include <linux/kthread.h>
35 #include <scsi/scsi.h>
36 #include <scsi/scsi_host.h>
37 #include <scsi/scsi_device.h>
38
39 #include "common.h"
40
41 struct backend_info
42 {
43         struct xenbus_device *dev;
44         struct vscsibk_info *info;
45 };
46
47
48 static int __vscsiif_name(struct backend_info *be, char *buf)
49 {
50         struct xenbus_device *dev = be->dev;
51         unsigned int domid, id;
52
53         sscanf(dev->nodename, "backend/vscsi/%u/%u", &domid, &id);
54         snprintf(buf, TASK_COMM_LEN, "vscsi.%u.%u", be->info->domid, id);
55
56         return 0;
57 }
58
59 static int scsiback_map(struct backend_info *be)
60 {
61         struct xenbus_device *dev = be->dev;
62         unsigned int ring_ref, evtchn;
63         int err;
64         char name[TASK_COMM_LEN];
65
66         err = xenbus_gather(XBT_NIL, dev->otherend,
67                         "ring-ref", "%u", &ring_ref,
68                         "event-channel", "%u", &evtchn, NULL);
69         if (err) {
70                 xenbus_dev_fatal(dev, err, "reading %s ring", dev->otherend);
71                 return err;
72         }
73
74         err = scsiback_init_sring(be->info, ring_ref, evtchn);
75         if (err)
76                 return err;
77
78         err = __vscsiif_name(be, name);
79         if (err) {
80                 xenbus_dev_error(dev, err, "get scsiback dev name");
81                 return err;
82         }
83
84         be->info->kthread = kthread_run(scsiback_schedule, be->info, name);
85         if (IS_ERR(be->info->kthread)) {
86                 err = PTR_ERR(be->info->kthread);
87                 be->info->kthread = NULL;
88                 xenbus_dev_error(be->dev, err, "start vscsiif");
89                 return err;
90         }
91
92         return 0;
93 }
94
95
96 struct scsi_device *scsiback_get_scsi_device(struct ids_tuple *phy)
97 {
98         struct Scsi_Host *shost;
99         struct scsi_device *sdev = NULL;
100
101         shost = scsi_host_lookup(phy->hst);
102         if (IS_ERR(shost)) {
103                 pr_err("scsiback: host%d doesn't exist\n", phy->hst);
104                 return NULL;
105         }
106         sdev   = scsi_device_lookup(shost, phy->chn, phy->tgt, phy->lun);
107         if (!sdev) {
108                 pr_err("scsiback: %d:%d:%d:%d doesn't exist\n",
109                        phy->hst, phy->chn, phy->tgt, phy->lun);
110                 scsi_host_put(shost);
111                 return NULL;
112         }
113
114         scsi_host_put(shost);
115         return (sdev);
116 }
117
118 #define VSCSIBACK_OP_ADD_OR_DEL_LUN     1
119 #define VSCSIBACK_OP_UPDATEDEV_STATE    2
120
121
122 static void scsiback_do_lun_hotplug(struct backend_info *be, int op)
123 {
124         int i, err = 0;
125         struct ids_tuple phy, vir;
126         int device_state;
127         char str[64], state_str[64];
128         char **dir;
129         unsigned int dir_n = 0;
130         struct xenbus_device *dev = be->dev;
131         struct scsi_device *sdev;
132
133         dir = xenbus_directory(XBT_NIL, dev->nodename, "vscsi-devs", &dir_n);
134         if (IS_ERR(dir))
135                 return;
136
137         for (i = 0; i < dir_n; i++) {
138                 
139                 /* read status */
140                 snprintf(state_str, sizeof(state_str), "vscsi-devs/%s/state", dir[i]);
141                 err = xenbus_scanf(XBT_NIL, dev->nodename, state_str, "%u",
142                         &device_state);
143                 if (XENBUS_EXIST_ERR(err))
144                         continue;
145
146                 /* physical SCSI device */
147                 snprintf(str, sizeof(str), "vscsi-devs/%s/p-dev", dir[i]);
148                 err = xenbus_scanf(XBT_NIL, dev->nodename, str,
149                         "%u:%u:%u:%u", &phy.hst, &phy.chn, &phy.tgt, &phy.lun);
150                 if (XENBUS_EXIST_ERR(err)) {
151                         xenbus_printf(XBT_NIL, dev->nodename, state_str,
152                                         "%d", XenbusStateClosed);
153                         continue;
154                 }
155
156                 /* virtual SCSI device */
157                 snprintf(str, sizeof(str), "vscsi-devs/%s/v-dev", dir[i]);
158                 err = xenbus_scanf(XBT_NIL, dev->nodename, str,
159                         "%u:%u:%u:%u", &vir.hst, &vir.chn, &vir.tgt, &vir.lun);
160                 if (XENBUS_EXIST_ERR(err)) {
161                         xenbus_printf(XBT_NIL, dev->nodename, state_str,
162                                         "%d", XenbusStateClosed);
163                         continue;
164                 }
165
166                 switch (op) {
167                 case VSCSIBACK_OP_ADD_OR_DEL_LUN:
168                         if (device_state == XenbusStateInitialising) {
169                                 sdev = scsiback_get_scsi_device(&phy);
170                                 if (!sdev)
171                                         xenbus_printf(XBT_NIL, dev->nodename, state_str, 
172                                                             "%d", XenbusStateClosed);
173                                 else {
174                                         err = scsiback_add_translation_entry(be->info, sdev, &vir);
175                                         if (!err) {
176                                                 if (xenbus_printf(XBT_NIL, dev->nodename, state_str, 
177                                                                     "%d", XenbusStateInitialised)) {
178                                                         pr_err("scsiback: xenbus_printf error %s\n",
179                                                                state_str);
180                                                         scsiback_del_translation_entry(be->info, &vir);
181                                                 }
182                                         } else {
183                                                 scsi_device_put(sdev);
184                                                 xenbus_printf(XBT_NIL, dev->nodename, state_str, 
185                                                                     "%d", XenbusStateClosed);
186                                         }
187                                 }
188                         }
189
190                         if (device_state == XenbusStateClosing) {
191                                 if (!scsiback_del_translation_entry(be->info, &vir)) {
192                                         if (xenbus_printf(XBT_NIL, dev->nodename, state_str, 
193                                                             "%d", XenbusStateClosed))
194                                                 pr_err("scsiback: xenbus_printf error %s\n",
195                                                        state_str);
196                                 }
197                         }
198                         break;
199
200                 case VSCSIBACK_OP_UPDATEDEV_STATE:
201                         if (device_state == XenbusStateInitialised) {
202                                 /* modify vscsi-devs/dev-x/state */
203                                 if (xenbus_printf(XBT_NIL, dev->nodename, state_str, 
204                                                     "%d", XenbusStateConnected)) {
205                                         pr_err("scsiback: xenbus_printf error %s\n",
206                                                state_str);
207                                         scsiback_del_translation_entry(be->info, &vir);
208                                         xenbus_printf(XBT_NIL, dev->nodename, state_str, 
209                                                             "%d", XenbusStateClosed);
210                                 }
211                         }
212                         break;
213                 /*When it is necessary, processing is added here.*/
214                 default:
215                         break;
216                 }
217         }
218
219         kfree(dir);
220         return ;
221 }
222
223
224 static void scsiback_frontend_changed(struct xenbus_device *dev,
225                                         enum xenbus_state frontend_state)
226 {
227         struct backend_info *be = dev_get_drvdata(&dev->dev);
228         int err;
229
230         switch (frontend_state) {
231         case XenbusStateInitialising:
232                 break;
233         case XenbusStateInitialised:
234                 err = scsiback_map(be);
235                 if (err)
236                         break;
237
238                 scsiback_do_lun_hotplug(be, VSCSIBACK_OP_ADD_OR_DEL_LUN);
239                 xenbus_switch_state(dev, XenbusStateConnected);
240
241                 break;
242         case XenbusStateConnected:
243
244                 scsiback_do_lun_hotplug(be, VSCSIBACK_OP_UPDATEDEV_STATE);
245
246                 if (dev->state == XenbusStateConnected)
247                         break;
248
249                 xenbus_switch_state(dev, XenbusStateConnected);
250
251                 break;
252
253         case XenbusStateClosing:
254                 scsiback_disconnect(be->info);
255                 xenbus_switch_state(dev, XenbusStateClosing);
256                 break;
257
258         case XenbusStateClosed:
259                 xenbus_switch_state(dev, XenbusStateClosed);
260                 if (xenbus_dev_is_online(dev))
261                         break;
262                 /* fall through if not online */
263         case XenbusStateUnknown:
264                 device_unregister(&dev->dev);
265                 break;
266
267         case XenbusStateReconfiguring:
268                 scsiback_do_lun_hotplug(be, VSCSIBACK_OP_ADD_OR_DEL_LUN);
269
270                 xenbus_switch_state(dev, XenbusStateReconfigured);
271
272                 break;
273
274         default:
275                 xenbus_dev_fatal(dev, -EINVAL, "saw state %d at frontend",
276                                         frontend_state);
277                 break;
278         }
279 }
280
281
282 static int scsiback_remove(struct xenbus_device *dev)
283 {
284         struct backend_info *be = dev_get_drvdata(&dev->dev);
285
286         if (be->info) {
287                 scsiback_disconnect(be->info);
288                 scsiback_release_translation_entry(be->info);
289                 scsiback_free(be->info);
290                 be->info = NULL;
291         }
292
293         kfree(be);
294         dev_set_drvdata(&dev->dev, NULL);
295
296         return 0;
297 }
298
299
300 static int scsiback_probe(struct xenbus_device *dev,
301                            const struct xenbus_device_id *id)
302 {
303         int err;
304         unsigned val = 0;
305
306         struct backend_info *be = kzalloc(sizeof(struct backend_info),
307                                           GFP_KERNEL);
308
309         DPRINTK("%p %d\n", dev, dev->otherend_id);
310
311         if (!be) {
312                 xenbus_dev_fatal(dev, -ENOMEM,
313                                  "allocating backend structure");
314                 return -ENOMEM;
315         }
316         be->dev = dev;
317         dev_set_drvdata(&dev->dev, be);
318
319         be->info = vscsibk_info_alloc(dev->otherend_id);
320         if (IS_ERR(be->info)) {
321                 err = PTR_ERR(be->info);
322                 be->info = NULL;
323                 xenbus_dev_fatal(dev, err, "creating scsihost interface");
324                 goto fail;
325         }
326
327         be->info->dev = dev;
328         be->info->irq = 0;
329         be->info->feature = 0;  /*default not HOSTMODE.*/
330
331         scsiback_init_translation_table(be->info);
332
333         err = xenbus_scanf(XBT_NIL, dev->nodename,
334                                 "feature-host", "%d", &val);
335         if (XENBUS_EXIST_ERR(err))
336                 val = 0;
337
338         if (val)
339                 be->info->feature = VSCSI_TYPE_HOST;
340
341         err = xenbus_switch_state(dev, XenbusStateInitWait);
342         if (err)
343                 goto fail;
344
345         return 0;
346
347
348 fail:
349         pr_warning("scsiback: %s failed\n",__FUNCTION__);
350         scsiback_remove(dev);
351
352         return err;
353 }
354
355
356 static const struct xenbus_device_id scsiback_ids[] = {
357         { "vscsi" },
358         { "" }
359 };
360
361 static DEFINE_XENBUS_DRIVER(scsiback, ,
362         .probe                  = scsiback_probe,
363         .remove                 = scsiback_remove,
364         .otherend_changed       = scsiback_frontend_changed
365 );
366
367 int __init scsiback_xenbus_init(void)
368 {
369         return xenbus_register_backend(&scsiback_driver);
370 }
371
372 void __exit scsiback_xenbus_unregister(void)
373 {
374         xenbus_unregister_driver(&scsiback_driver);
375 }