ia64/linux-2.6.18-xen.hg

view drivers/xen/scsifront/xenbus.c @ 601:e0c15322ff6d

pvSCSI: More fixes (including locking cleanups)

Signed-off-by: Tomonari Horikoshi <t.horikoshi@jp.fujitsu.com>
Signed-off-by: Jun Kamada <kama@jp.fujitsu.com>
author Keir Fraser <keir.fraser@citrix.com>
date Mon Jul 14 10:15:44 2008 +0100 (2008-07-14)
parents 132bae41625f
children
line source
1 /*
2 * Xen SCSI frontend driver
3 *
4 * Copyright (c) 2008, FUJITSU Limited
5 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License version 2
8 * as published by the Free Software Foundation; or, when distributed
9 * separately from the Linux kernel or incorporated into other
10 * software packages, subject to the following license:
11 *
12 * Permission is hereby granted, free of charge, to any person obtaining a copy
13 * of this source file (the "Software"), to deal in the Software without
14 * restriction, including without limitation the rights to use, copy, modify,
15 * merge, publish, distribute, sublicense, and/or sell copies of the Software,
16 * and to permit persons to whom the Software is furnished to do so, subject to
17 * the following conditions:
18 *
19 * The above copyright notice and this permission notice shall be included in
20 * all copies or substantial portions of the Software.
21 *
22 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
23 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
24 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
25 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
26 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
27 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
28 * IN THE SOFTWARE.
29 */
32 #include <linux/version.h>
33 #include "common.h"
35 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,11)
36 #define DEFAULT_TASK_COMM_LEN 16
37 #else
38 #define DEFAULT_TASK_COMM_LEN TASK_COMM_LEN
39 #endif
41 extern struct scsi_host_template scsifront_sht;
43 static void scsifront_free(struct vscsifrnt_info *info)
44 {
45 struct Scsi_Host *host = info->host;
47 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,14)
48 if (host->shost_state != SHOST_DEL) {
49 #else
50 if (!test_bit(SHOST_DEL, &host->shost_state)) {
51 #endif
52 scsi_remove_host(info->host);
53 }
55 if (info->ring_ref != GRANT_INVALID_REF) {
56 gnttab_end_foreign_access(info->ring_ref,
57 (unsigned long)info->ring.sring);
58 info->ring_ref = GRANT_INVALID_REF;
59 info->ring.sring = NULL;
60 }
62 if (info->irq)
63 unbind_from_irqhandler(info->irq, info);
64 info->irq = 0;
66 scsi_host_put(info->host);
67 }
70 static int scsifront_alloc_ring(struct vscsifrnt_info *info)
71 {
72 struct xenbus_device *dev = info->dev;
73 struct vscsiif_sring *sring;
74 int err = -ENOMEM;
77 info->ring_ref = GRANT_INVALID_REF;
79 /***** Frontend to Backend ring start *****/
80 sring = (struct vscsiif_sring *) __get_free_page(GFP_KERNEL);
81 if (!sring) {
82 xenbus_dev_fatal(dev, err, "fail to allocate shared ring (Front to Back)");
83 return err;
84 }
85 SHARED_RING_INIT(sring);
86 FRONT_RING_INIT(&info->ring, sring, PAGE_SIZE);
88 err = xenbus_grant_ring(dev, virt_to_mfn(sring));
89 if (err < 0) {
90 free_page((unsigned long) sring);
91 info->ring.sring = NULL;
92 xenbus_dev_fatal(dev, err, "fail to grant shared ring (Front to Back)");
93 goto free_sring;
94 }
95 info->ring_ref = err;
97 err = bind_listening_port_to_irqhandler(
98 dev->otherend_id, scsifront_intr,
99 SA_SAMPLE_RANDOM, "scsifront", info);
101 if (err <= 0) {
102 xenbus_dev_fatal(dev, err, "bind_listening_port_to_irqhandler");
103 goto free_sring;
104 }
105 info->irq = err;
107 return 0;
109 /* free resource */
110 free_sring:
111 scsifront_free(info);
113 return err;
114 }
117 static int scsifront_init_ring(struct vscsifrnt_info *info)
118 {
119 struct xenbus_device *dev = info->dev;
120 struct xenbus_transaction xbt;
121 int err;
123 DPRINTK("%s\n",__FUNCTION__);
125 err = scsifront_alloc_ring(info);
126 if (err)
127 return err;
128 DPRINTK("%u %u\n", info->ring_ref, info->evtchn);
130 again:
131 err = xenbus_transaction_start(&xbt);
132 if (err) {
133 xenbus_dev_fatal(dev, err, "starting transaction");
134 }
136 err = xenbus_printf(xbt, dev->nodename, "ring-ref", "%u",
137 info->ring_ref);
138 if (err) {
139 xenbus_dev_fatal(dev, err, "%s", "writing ring-ref");
140 goto fail;
141 }
143 err = xenbus_printf(xbt, dev->nodename, "event-channel", "%u",
144 irq_to_evtchn_port(info->irq));
146 if (err) {
147 xenbus_dev_fatal(dev, err, "%s", "writing event-channel");
148 goto fail;
149 }
151 err = xenbus_transaction_end(xbt, 0);
152 if (err) {
153 if (err == -EAGAIN)
154 goto again;
155 xenbus_dev_fatal(dev, err, "completing transaction");
156 goto free_sring;
157 }
159 return 0;
161 fail:
162 xenbus_transaction_end(xbt, 1);
163 free_sring:
164 /* free resource */
165 scsifront_free(info);
167 return err;
168 }
171 static int scsifront_probe(struct xenbus_device *dev,
172 const struct xenbus_device_id *id)
173 {
174 struct vscsifrnt_info *info;
175 struct Scsi_Host *host;
176 int i, err = -ENOMEM;
177 char name[DEFAULT_TASK_COMM_LEN];
179 host = scsi_host_alloc(&scsifront_sht, sizeof(*info));
180 if (!host) {
181 xenbus_dev_fatal(dev, err, "fail to allocate scsi host");
182 return err;
183 }
184 info = (struct vscsifrnt_info *) host->hostdata;
185 info->host = host;
188 dev->dev.driver_data = info;
189 info->dev = dev;
191 for (i = 0; i < VSCSIIF_MAX_REQS; i++) {
192 info->shadow[i].next_free = i + 1;
193 init_waitqueue_head(&(info->shadow[i].wq_reset));
194 info->shadow[i].wait_reset = 0;
195 }
196 info->shadow[VSCSIIF_MAX_REQS - 1].next_free = 0x0fff;
198 err = scsifront_init_ring(info);
199 if (err) {
200 scsi_host_put(host);
201 return err;
202 }
204 init_waitqueue_head(&info->wq);
205 spin_lock_init(&info->io_lock);
206 spin_lock_init(&info->shadow_lock);
208 snprintf(name, DEFAULT_TASK_COMM_LEN, "vscsiif.%d", info->host->host_no);
210 info->kthread = kthread_run(scsifront_schedule, info, name);
211 if (IS_ERR(info->kthread)) {
212 err = PTR_ERR(info->kthread);
213 info->kthread = NULL;
214 printk(KERN_ERR "scsifront: kthread start err %d\n", err);
215 goto free_sring;
216 }
218 host->max_id = VSCSIIF_MAX_TARGET;
219 host->max_channel = 0;
220 host->max_lun = VSCSIIF_MAX_LUN;
221 host->max_sectors = (VSCSIIF_SG_TABLESIZE - 1) * PAGE_SIZE / 512;
223 err = scsi_add_host(host, &dev->dev);
224 if (err) {
225 printk(KERN_ERR "scsifront: fail to add scsi host %d\n", err);
226 goto free_sring;
227 }
229 xenbus_switch_state(dev, XenbusStateInitialised);
231 return 0;
233 free_sring:
234 /* free resource */
235 scsifront_free(info);
236 return err;
237 }
239 static int scsifront_remove(struct xenbus_device *dev)
240 {
241 struct vscsifrnt_info *info = dev->dev.driver_data;
243 DPRINTK("%s: %s removed\n",__FUNCTION__ ,dev->nodename);
245 if (info->kthread) {
246 kthread_stop(info->kthread);
247 info->kthread = NULL;
248 }
250 scsifront_free(info);
252 return 0;
253 }
256 static int scsifront_disconnect(struct vscsifrnt_info *info)
257 {
258 struct xenbus_device *dev = info->dev;
259 struct Scsi_Host *host = info->host;
261 DPRINTK("%s: %s disconnect\n",__FUNCTION__ ,dev->nodename);
263 /*
264 When this function is executed, all devices of
265 Frontend have been deleted.
266 Therefore, it need not block I/O before remove_host.
267 */
269 scsi_remove_host(host);
270 xenbus_frontend_closed(dev);
272 return 0;
273 }
275 #define VSCSIFRONT_OP_ADD_LUN 1
276 #define VSCSIFRONT_OP_DEL_LUN 2
278 static void scsifront_do_lun_hotplug(struct vscsifrnt_info *info, int op)
279 {
280 struct xenbus_device *dev = info->dev;
281 int i, err = 0;
282 char str[64], state_str[64];
283 char **dir;
284 unsigned int dir_n = 0;
285 unsigned int device_state;
286 unsigned int hst, chn, tgt, lun;
287 struct scsi_device *sdev;
289 dir = xenbus_directory(XBT_NIL, dev->otherend, "vscsi-devs", &dir_n);
290 if (IS_ERR(dir))
291 return;
293 for (i = 0; i < dir_n; i++) {
294 /* read status */
295 snprintf(str, sizeof(str), "vscsi-devs/%s/state", dir[i]);
296 err = xenbus_scanf(XBT_NIL, dev->otherend, str, "%u",
297 &device_state);
298 if (XENBUS_EXIST_ERR(err))
299 continue;
301 /* virtual SCSI device */
302 snprintf(str, sizeof(str), "vscsi-devs/%s/v-dev", dir[i]);
303 err = xenbus_scanf(XBT_NIL, dev->otherend, str,
304 "%u:%u:%u:%u", &hst, &chn, &tgt, &lun);
305 if (XENBUS_EXIST_ERR(err))
306 continue;
308 /* front device state path */
309 snprintf(state_str, sizeof(state_str), "vscsi-devs/%s/state", dir[i]);
311 switch (op) {
312 case VSCSIFRONT_OP_ADD_LUN:
313 if (device_state == XenbusStateInitialised) {
314 sdev = scsi_device_lookup(info->host, chn, tgt, lun);
315 if (sdev) {
316 printk(KERN_ERR "scsifront: Device already in use.\n");
317 scsi_device_put(sdev);
318 xenbus_printf(XBT_NIL, dev->nodename,
319 state_str, "%d", XenbusStateClosed);
320 } else {
321 scsi_add_device(info->host, chn, tgt, lun);
322 xenbus_printf(XBT_NIL, dev->nodename,
323 state_str, "%d", XenbusStateConnected);
324 }
325 }
326 break;
327 case VSCSIFRONT_OP_DEL_LUN:
328 if (device_state == XenbusStateClosing) {
329 sdev = scsi_device_lookup(info->host, chn, tgt, lun);
330 if (sdev) {
331 scsi_remove_device(sdev);
332 scsi_device_put(sdev);
333 xenbus_printf(XBT_NIL, dev->nodename,
334 state_str, "%d", XenbusStateClosed);
335 }
336 }
337 break;
338 default:
339 break;
340 }
341 }
343 kfree(dir);
344 return;
345 }
350 static void scsifront_backend_changed(struct xenbus_device *dev,
351 enum xenbus_state backend_state)
352 {
353 struct vscsifrnt_info *info = dev->dev.driver_data;
355 DPRINTK("%p %u %u\n", dev, dev->state, backend_state);
357 switch (backend_state) {
358 case XenbusStateUnknown:
359 case XenbusStateInitialising:
360 case XenbusStateInitWait:
361 case XenbusStateClosed:
362 break;
364 case XenbusStateInitialised:
365 break;
367 case XenbusStateConnected:
368 if (xenbus_read_driver_state(dev->nodename) ==
369 XenbusStateInitialised) {
370 scsifront_do_lun_hotplug(info, VSCSIFRONT_OP_ADD_LUN);
371 }
373 if (dev->state == XenbusStateConnected)
374 break;
376 xenbus_switch_state(dev, XenbusStateConnected);
377 break;
379 case XenbusStateClosing:
380 scsifront_disconnect(info);
381 break;
383 case XenbusStateReconfiguring:
384 scsifront_do_lun_hotplug(info, VSCSIFRONT_OP_DEL_LUN);
385 xenbus_switch_state(dev, XenbusStateReconfiguring);
386 break;
388 case XenbusStateReconfigured:
389 scsifront_do_lun_hotplug(info, VSCSIFRONT_OP_ADD_LUN);
390 xenbus_switch_state(dev, XenbusStateConnected);
391 break;
392 }
393 }
396 static struct xenbus_device_id scsifront_ids[] = {
397 { "vscsi" },
398 { "" }
399 };
402 static struct xenbus_driver scsifront_driver = {
403 .name = "vscsi",
404 .owner = THIS_MODULE,
405 .ids = scsifront_ids,
406 .probe = scsifront_probe,
407 .remove = scsifront_remove,
408 /* .resume = scsifront_resume, */
409 .otherend_changed = scsifront_backend_changed,
410 };
412 int scsifront_xenbus_init(void)
413 {
414 return xenbus_register_frontend(&scsifront_driver);
415 }
417 void scsifront_xenbus_unregister(void)
418 {
419 xenbus_unregister_driver(&scsifront_driver);
420 }