ia64/linux-2.6.18-xen.hg

view drivers/xen/scsiback/xenbus.c @ 794:be85b1d7a52b

pvSCSI: add new device assignment mode

Add a new device assignment mode, which assigns whole HBA
(SCSI host) to guest domain. Current implementation requires SCSI
command emulation on backend driver, and it causes limitations for
some SCSI commands. (Please see
"http://www.xen.org/files/xensummit_tokyo/24_Hitoshi%20Matsumoto_en.pdf"
for detail about why we need the new assignment mode.

SCSI command emulation on backend driver is bypassed when "host" mode
is specified.

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 Tue Feb 17 11:17:11 2009 +0000 (2009-02-17)
parents 132bae41625f
children
line source
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 */
33 #include <stdarg.h>
34 #include <linux/module.h>
35 #include <linux/kthread.h>
36 #include <scsi/scsi.h>
37 #include <scsi/scsi_host.h>
38 #include <scsi/scsi_device.h>
40 #include "common.h"
42 struct backend_info
43 {
44 struct xenbus_device *dev;
45 struct vscsibk_info *info;
46 };
49 static int __vscsiif_name(struct backend_info *be, char *buf)
50 {
51 struct xenbus_device *dev = be->dev;
52 unsigned int domid, id;
54 sscanf(dev->nodename, "backend/vscsi/%u/%u", &domid, &id);
55 snprintf(buf, TASK_COMM_LEN, "vscsi.%u.%u", be->info->domid, id);
57 return 0;
58 }
60 static int scsiback_map(struct backend_info *be)
61 {
62 struct xenbus_device *dev = be->dev;
63 unsigned long ring_ref;
64 unsigned int evtchn;
65 int err;
66 char name[TASK_COMM_LEN];
68 err = xenbus_gather(XBT_NIL, dev->otherend,
69 "ring-ref", "%lu", &ring_ref,
70 "event-channel", "%u", &evtchn, NULL);
71 if (err) {
72 xenbus_dev_fatal(dev, err, "reading %s ring", dev->otherend);
73 return err;
74 }
76 err = scsiback_init_sring(be->info, ring_ref, evtchn);
77 if (err)
78 return err;
80 err = __vscsiif_name(be, name);
81 if (err) {
82 xenbus_dev_error(dev, err, "get scsiback dev name");
83 return err;
84 }
86 be->info->kthread = kthread_run(scsiback_schedule, be->info, name);
87 if (IS_ERR(be->info->kthread)) {
88 err = PTR_ERR(be->info->kthread);
89 be->info->kthread = NULL;
90 xenbus_dev_error(be->dev, err, "start vscsiif");
91 return err;
92 }
94 return 0;
95 }
98 struct scsi_device *scsiback_get_scsi_device(struct ids_tuple *phy)
99 {
100 struct Scsi_Host *shost;
101 struct scsi_device *sdev = NULL;
103 shost = scsi_host_lookup(phy->hst);
104 if (IS_ERR(shost)) {
105 printk(KERN_ERR "scsiback: host%d doesn't exist.\n",
106 phy->hst);
107 return NULL;
108 }
109 sdev = scsi_device_lookup(shost, phy->chn, phy->tgt, phy->lun);
110 if (!sdev) {
111 printk(KERN_ERR "scsiback: %d:%d:%d:%d doesn't exist.\n",
112 phy->hst, phy->chn, phy->tgt, phy->lun);
113 scsi_host_put(shost);
114 return NULL;
115 }
117 scsi_host_put(shost);
118 return (sdev);
119 }
121 #define VSCSIBACK_OP_ADD_OR_DEL_LUN 1
122 #define VSCSIBACK_OP_UPDATEDEV_STATE 2
125 static void scsiback_do_lun_hotplug(struct backend_info *be, int op)
126 {
127 int i, err = 0;
128 struct ids_tuple phy, vir;
129 int device_state;
130 char str[64], state_str[64];
131 char **dir;
132 unsigned int dir_n = 0;
133 struct xenbus_device *dev = be->dev;
134 struct scsi_device *sdev;
136 dir = xenbus_directory(XBT_NIL, dev->nodename, "vscsi-devs", &dir_n);
137 if (IS_ERR(dir))
138 return;
140 for (i = 0; i < dir_n; i++) {
142 /* read status */
143 snprintf(state_str, sizeof(state_str), "vscsi-devs/%s/state", dir[i]);
144 err = xenbus_scanf(XBT_NIL, dev->nodename, state_str, "%u",
145 &device_state);
146 if (XENBUS_EXIST_ERR(err))
147 continue;
149 /* physical SCSI device */
150 snprintf(str, sizeof(str), "vscsi-devs/%s/p-dev", dir[i]);
151 err = xenbus_scanf(XBT_NIL, dev->nodename, str,
152 "%u:%u:%u:%u", &phy.hst, &phy.chn, &phy.tgt, &phy.lun);
153 if (XENBUS_EXIST_ERR(err)) {
154 xenbus_printf(XBT_NIL, dev->nodename, state_str,
155 "%d", XenbusStateClosed);
156 continue;
157 }
159 /* virtual SCSI device */
160 snprintf(str, sizeof(str), "vscsi-devs/%s/v-dev", dir[i]);
161 err = xenbus_scanf(XBT_NIL, dev->nodename, str,
162 "%u:%u:%u:%u", &vir.hst, &vir.chn, &vir.tgt, &vir.lun);
163 if (XENBUS_EXIST_ERR(err)) {
164 xenbus_printf(XBT_NIL, dev->nodename, state_str,
165 "%d", XenbusStateClosed);
166 continue;
167 }
169 switch (op) {
170 case VSCSIBACK_OP_ADD_OR_DEL_LUN:
171 if (device_state == XenbusStateInitialising) {
172 sdev = scsiback_get_scsi_device(&phy);
173 if (!sdev)
174 xenbus_printf(XBT_NIL, dev->nodename, state_str,
175 "%d", XenbusStateClosed);
176 else {
177 err = scsiback_add_translation_entry(be->info, sdev, &vir);
178 if (!err) {
179 if (xenbus_printf(XBT_NIL, dev->nodename, state_str,
180 "%d", XenbusStateInitialised)) {
181 printk(KERN_ERR "scsiback: xenbus_printf error %s\n", state_str);
182 scsiback_del_translation_entry(be->info, &vir);
183 }
184 } else {
185 scsi_device_put(sdev);
186 xenbus_printf(XBT_NIL, dev->nodename, state_str,
187 "%d", XenbusStateClosed);
188 }
189 }
190 }
192 if (device_state == XenbusStateClosing) {
193 if (!scsiback_del_translation_entry(be->info, &vir)) {
194 if (xenbus_printf(XBT_NIL, dev->nodename, state_str,
195 "%d", XenbusStateClosed))
196 printk(KERN_ERR "scsiback: xenbus_printf error %s\n", state_str);
197 }
198 }
199 break;
201 case VSCSIBACK_OP_UPDATEDEV_STATE:
202 if (device_state == XenbusStateInitialised) {
203 /* modify vscsi-devs/dev-x/state */
204 if (xenbus_printf(XBT_NIL, dev->nodename, state_str,
205 "%d", XenbusStateConnected)) {
206 printk(KERN_ERR "scsiback: xenbus_printf error %s\n", 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 }
219 kfree(dir);
220 return ;
221 }
224 static void scsiback_frontend_changed(struct xenbus_device *dev,
225 enum xenbus_state frontend_state)
226 {
227 struct backend_info *be = dev->dev.driver_data;
228 int err;
230 switch (frontend_state) {
231 case XenbusStateInitialising:
232 break;
233 case XenbusStateInitialised:
234 err = scsiback_map(be);
235 if (err)
236 break;
238 scsiback_do_lun_hotplug(be, VSCSIBACK_OP_ADD_OR_DEL_LUN);
239 xenbus_switch_state(dev, XenbusStateConnected);
241 break;
242 case XenbusStateConnected:
244 scsiback_do_lun_hotplug(be, VSCSIBACK_OP_UPDATEDEV_STATE);
246 if (dev->state == XenbusStateConnected)
247 break;
249 xenbus_switch_state(dev, XenbusStateConnected);
251 break;
253 case XenbusStateClosing:
254 scsiback_disconnect(be->info);
255 xenbus_switch_state(dev, XenbusStateClosing);
256 break;
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;
267 case XenbusStateReconfiguring:
268 scsiback_do_lun_hotplug(be, VSCSIBACK_OP_ADD_OR_DEL_LUN);
270 xenbus_switch_state(dev, XenbusStateReconfigured);
272 break;
274 default:
275 xenbus_dev_fatal(dev, -EINVAL, "saw state %d at frontend",
276 frontend_state);
277 break;
278 }
279 }
282 static int scsiback_remove(struct xenbus_device *dev)
283 {
284 struct backend_info *be = dev->dev.driver_data;
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 }
293 kfree(be);
294 dev->dev.driver_data = NULL;
296 return 0;
297 }
300 static int scsiback_probe(struct xenbus_device *dev,
301 const struct xenbus_device_id *id)
302 {
303 int err;
304 unsigned val = 0;
306 struct backend_info *be = kzalloc(sizeof(struct backend_info),
307 GFP_KERNEL);
309 DPRINTK("%p %d\n", dev, dev->otherend_id);
311 if (!be) {
312 xenbus_dev_fatal(dev, -ENOMEM,
313 "allocating backend structure");
314 return -ENOMEM;
315 }
316 be->dev = dev;
317 dev->dev.driver_data = be;
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 }
327 be->info->dev = dev;
328 be->info->irq = 0;
329 be->info->feature = 0; /*default not HOSTMODE.*/
331 scsiback_init_translation_table(be->info);
333 err = xenbus_scanf(XBT_NIL, dev->nodename,
334 "feature-host", "%d", &val);
335 if (XENBUS_EXIST_ERR(err))
336 val = 0;
338 if (val)
339 be->info->feature = VSCSI_TYPE_HOST;
341 err = xenbus_switch_state(dev, XenbusStateInitWait);
342 if (err)
343 goto fail;
345 return 0;
348 fail:
349 printk(KERN_WARNING "scsiback: %s failed\n",__FUNCTION__);
350 scsiback_remove(dev);
352 return err;
353 }
356 static struct xenbus_device_id scsiback_ids[] = {
357 { "vscsi" },
358 { "" }
359 };
361 static struct xenbus_driver scsiback = {
362 .name = "vscsi",
363 .owner = THIS_MODULE,
364 .ids = scsiback_ids,
365 .probe = scsiback_probe,
366 .remove = scsiback_remove,
367 .otherend_changed = scsiback_frontend_changed
368 };
370 int scsiback_xenbus_init(void)
371 {
372 return xenbus_register_backend(&scsiback);
373 }
375 void scsiback_xenbus_unregister(void)
376 {
377 xenbus_unregister_driver(&scsiback);
378 }