2 * Xen SCSI backend driver
4 * Copyright (c) 2008, FUJITSU Limited
6 * Based on the blkback driver code.
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:
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:
21 * The above copyright notice and this permission notice shall be included in
22 * all copies or substantial portions of the Software.
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
34 #include <linux/kthread.h>
35 #include <scsi/scsi.h>
36 #include <scsi/scsi_host.h>
37 #include <scsi/scsi_device.h>
43 struct xenbus_device *dev;
44 struct vscsibk_info *info;
48 static int __vscsiif_name(struct backend_info *be, char *buf)
50 struct xenbus_device *dev = be->dev;
51 unsigned int domid, id;
53 sscanf(dev->nodename, "backend/vscsi/%u/%u", &domid, &id);
54 snprintf(buf, TASK_COMM_LEN, "vscsi.%u.%u", be->info->domid, id);
59 static int scsiback_map(struct backend_info *be)
61 struct xenbus_device *dev = be->dev;
62 unsigned int ring_ref, evtchn;
64 char name[TASK_COMM_LEN];
66 err = xenbus_gather(XBT_NIL, dev->otherend,
67 "ring-ref", "%u", &ring_ref,
68 "event-channel", "%u", &evtchn, NULL);
70 xenbus_dev_fatal(dev, err, "reading %s ring", dev->otherend);
74 err = scsiback_init_sring(be->info, ring_ref, evtchn);
78 err = __vscsiif_name(be, name);
80 xenbus_dev_error(dev, err, "get scsiback dev name");
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");
96 struct scsi_device *scsiback_get_scsi_device(struct ids_tuple *phy)
98 struct Scsi_Host *shost;
99 struct scsi_device *sdev = NULL;
101 shost = scsi_host_lookup(phy->hst);
103 pr_err("scsiback: host%d doesn't exist\n", phy->hst);
106 sdev = scsi_device_lookup(shost, phy->chn, phy->tgt, phy->lun);
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);
114 scsi_host_put(shost);
118 #define VSCSIBACK_OP_ADD_OR_DEL_LUN 1
119 #define VSCSIBACK_OP_UPDATEDEV_STATE 2
122 static void scsiback_do_lun_hotplug(struct backend_info *be, int op)
125 struct ids_tuple phy, vir;
127 char str[64], state_str[64];
129 unsigned int dir_n = 0;
130 struct xenbus_device *dev = be->dev;
131 struct scsi_device *sdev;
133 dir = xenbus_directory(XBT_NIL, dev->nodename, "vscsi-devs", &dir_n);
137 for (i = 0; i < dir_n; i++) {
140 snprintf(state_str, sizeof(state_str), "vscsi-devs/%s/state", dir[i]);
141 err = xenbus_scanf(XBT_NIL, dev->nodename, state_str, "%u",
143 if (XENBUS_EXIST_ERR(err))
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);
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);
167 case VSCSIBACK_OP_ADD_OR_DEL_LUN:
168 if (device_state == XenbusStateInitialising) {
169 sdev = scsiback_get_scsi_device(&phy);
171 xenbus_printf(XBT_NIL, dev->nodename, state_str,
172 "%d", XenbusStateClosed);
174 err = scsiback_add_translation_entry(be->info, sdev, &vir);
176 if (xenbus_printf(XBT_NIL, dev->nodename, state_str,
177 "%d", XenbusStateInitialised)) {
178 pr_err("scsiback: xenbus_printf error %s\n",
180 scsiback_del_translation_entry(be->info, &vir);
183 scsi_device_put(sdev);
184 xenbus_printf(XBT_NIL, dev->nodename, state_str,
185 "%d", XenbusStateClosed);
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",
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",
207 scsiback_del_translation_entry(be->info, &vir);
208 xenbus_printf(XBT_NIL, dev->nodename, state_str,
209 "%d", XenbusStateClosed);
213 /*When it is necessary, processing is added here.*/
224 static void scsiback_frontend_changed(struct xenbus_device *dev,
225 enum xenbus_state frontend_state)
227 struct backend_info *be = dev_get_drvdata(&dev->dev);
230 switch (frontend_state) {
231 case XenbusStateInitialising:
233 case XenbusStateInitialised:
234 err = scsiback_map(be);
238 scsiback_do_lun_hotplug(be, VSCSIBACK_OP_ADD_OR_DEL_LUN);
239 xenbus_switch_state(dev, XenbusStateConnected);
242 case XenbusStateConnected:
244 scsiback_do_lun_hotplug(be, VSCSIBACK_OP_UPDATEDEV_STATE);
246 if (dev->state == XenbusStateConnected)
249 xenbus_switch_state(dev, XenbusStateConnected);
253 case XenbusStateClosing:
254 scsiback_disconnect(be->info);
255 xenbus_switch_state(dev, XenbusStateClosing);
258 case XenbusStateClosed:
259 xenbus_switch_state(dev, XenbusStateClosed);
260 if (xenbus_dev_is_online(dev))
262 /* fall through if not online */
263 case XenbusStateUnknown:
264 device_unregister(&dev->dev);
267 case XenbusStateReconfiguring:
268 scsiback_do_lun_hotplug(be, VSCSIBACK_OP_ADD_OR_DEL_LUN);
270 xenbus_switch_state(dev, XenbusStateReconfigured);
275 xenbus_dev_fatal(dev, -EINVAL, "saw state %d at frontend",
282 static int scsiback_remove(struct xenbus_device *dev)
284 struct backend_info *be = dev_get_drvdata(&dev->dev);
287 scsiback_disconnect(be->info);
288 scsiback_release_translation_entry(be->info);
289 scsiback_free(be->info);
294 dev_set_drvdata(&dev->dev, NULL);
300 static int scsiback_probe(struct xenbus_device *dev,
301 const struct xenbus_device_id *id)
306 struct backend_info *be = kzalloc(sizeof(struct backend_info),
309 DPRINTK("%p %d\n", dev, dev->otherend_id);
312 xenbus_dev_fatal(dev, -ENOMEM,
313 "allocating backend structure");
317 dev_set_drvdata(&dev->dev, be);
319 be->info = vscsibk_info_alloc(dev->otherend_id);
320 if (IS_ERR(be->info)) {
321 err = PTR_ERR(be->info);
323 xenbus_dev_fatal(dev, err, "creating scsihost interface");
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))
339 be->info->feature = VSCSI_TYPE_HOST;
341 err = xenbus_switch_state(dev, XenbusStateInitWait);
349 pr_warning("scsiback: %s failed\n",__FUNCTION__);
350 scsiback_remove(dev);
356 static const struct xenbus_device_id scsiback_ids[] = {
361 static DEFINE_XENBUS_DRIVER(scsiback, ,
362 .probe = scsiback_probe,
363 .remove = scsiback_remove,
364 .otherend_changed = scsiback_frontend_changed
367 int __init scsiback_xenbus_init(void)
369 return xenbus_register_backend(&scsiback_driver);
372 void __exit scsiback_xenbus_unregister(void)
374 xenbus_unregister_driver(&scsiback_driver);