#include /* Needed by all modules */ #include /* Needed for KERN_ALERT */ #include /* We are doing something with Xen */ #include #include "xen_buf.h" struct vdevbbk_info { struct xenbus_device *dev; domid_t domid; unsigned int irq; // struct vscsiif_back_ring ring; int ring_error; spinlock_t ring_lock; atomic_t nr_unreplied_reqs; spinlock_t vdevb_lock; struct list_head vdevb_entry_lists; wait_queue_head_t waiting_to_free; }; // This is where we set up path watchers and event channels static void backend_connect(struct xenbus_device *dev) { pr_log("Connecting the backend now\n"); } // This will destroy event channel handlers static void backend_disconnect(struct xenbus_device *dev) { pr_log("Connecting the backend now\n"); } // We try to switch to the next state from a previous one static void set_backend_state(struct xenbus_device *dev, enum xenbus_state state) { //pr_log("dev->state: %s-%d, state: %s-%d\n", xenbus_state_array[dev->state], dev->state, xenbus_state_array[state], state); while (dev->state != state) { switch (dev->state) { case XenbusStateInitialising: switch (state) { case XenbusStateInitWait: case XenbusStateConnected: case XenbusStateClosing: xenbus_switch_state(dev, XenbusStateInitWait); break; case XenbusStateClosed: xenbus_switch_state(dev, XenbusStateClosed); break; default: BUG(); } break; case XenbusStateClosed: switch (state) { case XenbusStateInitWait: case XenbusStateConnected: xenbus_switch_state(dev, XenbusStateInitWait); break; case XenbusStateClosing: xenbus_switch_state(dev, XenbusStateClosing); break; default: BUG(); } break; case XenbusStateInitWait: switch (state) { case XenbusStateConnected: backend_connect(dev); xenbus_switch_state(dev, XenbusStateConnected); break; case XenbusStateClosing: case XenbusStateClosed: xenbus_switch_state(dev, XenbusStateClosing); break; default: BUG(); } break; case XenbusStateConnected: switch (state) { case XenbusStateInitWait: case XenbusStateClosing: case XenbusStateClosed: backend_disconnect(dev); xenbus_switch_state(dev, XenbusStateClosing); break; default: BUG(); } break; case XenbusStateClosing: switch (state) { case XenbusStateInitWait: case XenbusStateConnected: case XenbusStateClosed: xenbus_switch_state(dev, XenbusStateClosed); break; default: BUG(); } break; default: BUG(); } } } // The function is called on activation of the device static int xen_vdevb_be_probe(struct xenbus_device *dev, const struct xenbus_device_id *id) { struct vdevbbk_info *info = NULL; int ret = 0; pr_log("Probe called. We are good to go.\n"); pr_log(" %p %d\n", dev, dev->otherend_id); /* Allocating memory for private structure */ info = kzalloc(sizeof(struct vdevbbk_info), GFP_KERNEL); if (!info) { xenbus_dev_fatal(dev, -ENOMEM, "allocating backend structure"); return -ENOMEM; } info->dev = dev; dev_set_drvdata(&dev->dev, info); info->domid = dev->otherend_id; pr_log("info->domid: %d\n", info->domid); pr_log("devicetype: %s, nodename: %s, otherend: %s\n", dev->devicetype, dev->nodename, dev->otherend); #if 0 spin_lock_init(&info->ring_lock); info->ring_error = 0; atomic_set(&info->nr_unreplied_reqs, 0); init_waitqueue_head(&info->waiting_to_free); info->irq = 0; INIT_LIST_HEAD(&info->vdevb_entry_lists); spin_lock_init(&info->vdevb_lock); #endif ret = xenbus_printf(XBT_NIL, dev->nodename, "vdevb-version", "%s", "0.1"); if (ret) xenbus_dev_error(dev, ret, "writing vdevb-version"); ret = xenbus_switch_state(dev, XenbusStateInitialising); if (ret) goto error; return 0; error: pr_warn("%s failed\n", __func__); kfree(info); dev_set_drvdata(&dev->dev, NULL); return ret; } static int xen_vdevb_be_remove(struct xenbus_device *dev) { pr_log("\n"); return 0; } // The function is called on a state change of the frontend driver static void xen_vdevb_be_frontend_changed(struct xenbus_device *dev, enum xenbus_state frontend_state) { struct vdevbbk_info *info = dev_get_drvdata(&dev->dev); pr_log("dev->state: %s-%d, frontend_state: %s-%d\n", xenbus_state_array[dev->state], dev->state, xenbus_state_array[frontend_state], frontend_state); switch (frontend_state) { case XenbusStateInitialising: set_backend_state(dev, XenbusStateInitWait); break; case XenbusStateInitialised: break; case XenbusStateConnected: set_backend_state(dev, XenbusStateConnected); break; case XenbusStateClosing: set_backend_state(dev, XenbusStateClosing); break; case XenbusStateClosed: set_backend_state(dev, XenbusStateClosed); if (xenbus_dev_is_online(dev)) break; /* fall through if not online */ case XenbusStateUnknown: set_backend_state(dev, XenbusStateClosed); device_unregister(&dev->dev); break; default: xenbus_dev_fatal(dev, -EINVAL, "saw state %s (%d) at frontend", xenbus_strstate(frontend_state), frontend_state); break; } } // This defines the name of the devices the driver reacts to static const struct xenbus_device_id xen_vdevb_be_ids[] = { { "vdevb" }, { "" } }; // We set up the callback functions static struct xenbus_driver xen_vdevb_be_driver = { .ids = xen_vdevb_be_ids, .probe = xen_vdevb_be_probe, .remove = xen_vdevb_be_remove, .otherend_changed = xen_vdevb_be_frontend_changed, }; // On loading this kernel module, we register as a frontend driver static int __init xen_vdevb_be_init(void) { pr_log("xen_domain_type: %d, xen_domain: %d\n", xen_domain_type,xen_domain()); pr_log("Hello World!\n"); return xenbus_register_backend(&xen_vdevb_be_driver); } module_init(xen_vdevb_be_init); // ...and on unload we unregister static void __exit xen_vdevb_be_exit(void) { xenbus_unregister_driver(&xen_vdevb_be_driver); pr_log("Goodbye world.\n"); } module_exit(xen_vdevb_be_exit); MODULE_LICENSE("GPL"); MODULE_ALIAS("xen-clk-backend :vdevb");