static void backend_changed(struct xenbus_device *dev, enum xenbus_state backend_state) { switch (backend_state) { case XenbusStateInitialised: case XenbusStateConnected: if (dev->state == XenbusStateConnected) break; if (!xenbus_read_unsigned(dev->otherend, "feature-protocol-v2", 0)) { xenbus_dev_fatal(dev, -EINVAL, "vTPM protocol 2 required"); return; } xenbus_switch_state(dev, XenbusStateConnected); break; case XenbusStateClosing: case XenbusStateClosed: device_unregister(&dev->dev); xenbus_frontend_closed(dev); break; default: break; } }
static void xenkbd_backend_changed(struct xenbus_device *dev, enum xenbus_state backend_state) { struct xenkbd_info *info = dev_get_drvdata(&dev->dev); int ret, val; switch (backend_state) { case XenbusStateInitialising: case XenbusStateInitialised: case XenbusStateReconfiguring: case XenbusStateReconfigured: case XenbusStateUnknown: break; case XenbusStateInitWait: InitWait: ret = xenbus_scanf(XBT_NIL, info->xbdev->otherend, "feature-abs-pointer", "%d", &val); if (ret < 0) val = 0; if (val) { ret = xenbus_printf(XBT_NIL, info->xbdev->nodename, "request-abs-pointer", "1"); if (ret) pr_warning("xenkbd: can't request abs-pointer"); } xenbus_switch_state(dev, XenbusStateConnected); break; case XenbusStateConnected: /* * Work around xenbus race condition: If backend goes * through InitWait to Connected fast enough, we can * get Connected twice here. */ if (dev->state != XenbusStateConnected) goto InitWait; /* no InitWait seen yet, fudge it */ /* Set input abs params to match backend screen res */ if (xenbus_scanf(XBT_NIL, info->xbdev->otherend, "width", "%d", &val) > 0) input_set_abs_params(info->ptr, ABS_X, 0, val, 0, 0); if (xenbus_scanf(XBT_NIL, info->xbdev->otherend, "height", "%d", &val) > 0) input_set_abs_params(info->ptr, ABS_Y, 0, val, 0, 0); break; case XenbusStateClosed: if (dev->state == XenbusStateClosed) break; /* Missed the backend's CLOSING state -- fallthrough */ case XenbusStateClosing: xenbus_frontend_closed(dev); break; } }
/** * Handle a change to the keyboard device's backend. * This effectively moves us through the XenBus negotiation FSM. */ static void oxtkbd_backend_changed(struct xenbus_device *dev, enum xenbus_state backend_state) { int val; struct openxt_kbd_info *info = dev_get_drvdata(&dev->dev); switch (backend_state) { case XenbusStateInitialising: case XenbusStateInitialised: case XenbusStateReconfiguring: case XenbusStateReconfigured: case XenbusStateUnknown: break; case XenbusStateInitWait: InitWait: xenbus_switch_state(dev, XenbusStateConnected); break; case XenbusStateConnected: /* * Work around xenbus race condition: If backend goes * through InitWait to Connected fast enough, we can * get Connected twice here. */ if (dev->state != XenbusStateConnected) goto InitWait; /* no InitWait seen yet, fudge it */ //Once we connect, try to adjust the screen width and height //to match the width and height stored in the XenStore. if (xenbus_scanf(XBT_NIL, info->xbdev->otherend, "width", "%d", &val) > 0) { input_set_abs_params(info->absolute_pointer, ABS_X, 0, val, 0, 0); input_set_abs_params(info->absolute_pointer, ABS_MT_POSITION_X, 0, val, 0, 0); } if (xenbus_scanf(XBT_NIL, info->xbdev->otherend, "height", "%d", &val) > 0) { input_set_abs_params(info->absolute_pointer, ABS_Y, 0, val, 0, 0); input_set_abs_params(info->absolute_pointer, ABS_MT_POSITION_Y, 0, val, 0, 0); } break; case XenbusStateClosed: if (dev->state == XenbusStateClosed) break; /* Missed the backend's CLOSING state -- fallthrough */ case XenbusStateClosing: xenbus_frontend_closed(dev); break; } }
static void usbfront_disconnect(struct xenbus_device *dev) { struct usbfront_info *info = dev->dev.driver_data; struct usb_hcd *hcd = info_to_hcd(info); usb_remove_hcd(hcd); if (info->kthread) { kthread_stop(info->kthread); info->kthread = NULL; } xenbus_frontend_closed(dev); }
/** * Handle the change of state of the backend to Closing. We must delete our * device-layer structures now, to ensure that writes are flushed through to * the backend. Once is this done, we can switch to Closed in * acknowledgement. */ static void ixpfront_closing(struct ixpfront_info *info) { /* No more gnttab callback work. */ //gnttab_cancel_free_callback(&info->callback); /* Flush gnttab callback work. Must be done with no locks held. */ //flush_scheduled_work(); if (info->xbdev) xenbus_frontend_closed(info->xbdev); printk(KERN_ERR "Closing...\n"); }
static void xenkbd_backend_changed(struct xenbus_device *dev, enum xenbus_state backend_state) { struct xenkbd_info *info = dev_get_drvdata(&dev->dev); int ret, val; switch (backend_state) { case XenbusStateInitialising: case XenbusStateInitialised: case XenbusStateReconfiguring: case XenbusStateReconfigured: case XenbusStateUnknown: case XenbusStateClosed: break; case XenbusStateInitWait: InitWait: ret = xenbus_scanf(XBT_NIL, info->xbdev->otherend, "feature-abs-pointer", "%d", &val); if (ret < 0) val = 0; if (val) { ret = xenbus_printf(XBT_NIL, info->xbdev->nodename, "request-abs-pointer", "1"); if (ret) pr_warning("xenkbd: can't request abs-pointer"); } xenbus_switch_state(dev, XenbusStateConnected); break; case XenbusStateConnected: if (dev->state != XenbusStateConnected) goto InitWait; if (xenbus_scanf(XBT_NIL, info->xbdev->otherend, "width", "%d", &val) > 0) input_set_abs_params(info->ptr, ABS_X, 0, val, 0, 0); if (xenbus_scanf(XBT_NIL, info->xbdev->otherend, "height", "%d", &val) > 0) input_set_abs_params(info->ptr, ABS_Y, 0, val, 0, 0); break; case XenbusStateClosing: xenbus_frontend_closed(dev); break; } }
/* add for vmdq migrate.When the device is vmdq_vnic ,return */ if(0 == strcmp(xendev->devicetype, VMDQ_VNIC)){ return 0; } int err = xenbus_gather(XBT_NIL, xendev->nodename, id_node, "%i", &xendev->otherend_id, path_node, NULL, &xendev->otherend, NULL); if (err) { xenbus_dev_fatal(xendev, err, "reading other end details from %s", xendev->nodename); return err; } if (strlen(xendev->otherend) == 0 || !xenbus_exists(XBT_NIL, xendev->otherend, "")) { xenbus_dev_fatal(xendev, -ENOENT, "unable to read other end from %s. " "missing or inaccessible.", xendev->nodename); free_otherend_details(xendev); return -ENOENT; } return 0; } PARAVIRT_EXPORT_SYMBOL(xenbus_read_otherend_details); #if defined(CONFIG_XEN) || defined(MODULE) static int read_backend_details(struct xenbus_device *xendev) { return xenbus_read_otherend_details(xendev, "backend-id", "backend"); } static void otherend_changed(struct xenbus_watch *watch, const char **vec, unsigned int len) #else /* !CONFIG_XEN && !MODULE */ void xenbus_otherend_changed(struct xenbus_watch *watch, const char **vec, unsigned int len, int ignore_on_shutdown) #endif /* CONFIG_XEN || MODULE */ { struct xenbus_device *dev = container_of(watch, struct xenbus_device, otherend_watch); struct xenbus_driver *drv = to_xenbus_driver(dev->dev.driver); enum xenbus_state state; /* Protect us against watches firing on old details when the otherend details change, say immediately after a resume. */ if (!dev->otherend || strncmp(dev->otherend, vec[XS_WATCH_PATH], strlen(dev->otherend))) { dev_dbg(&dev->dev, "Ignoring watch at %s", vec[XS_WATCH_PATH]); return; } state = xenbus_read_driver_state(dev->otherend); dev_dbg(&dev->dev, "state is %d (%s), %s, %s", state, xenbus_strstate(state), dev->otherend_watch.node, vec[XS_WATCH_PATH]); #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,16) /* * Ignore xenbus transitions during shutdown. This prevents us doing * work that can fail e.g., when the rootfs is gone. */ if (system_state > SYSTEM_RUNNING) { /* If we're frontend, drive the state machine to Closed. */ /* This should cause the backend to release our resources. */ # if defined(CONFIG_XEN) || defined(MODULE) const struct xen_bus_type *bus = container_of(dev->dev.bus, struct xen_bus_type, bus); int ignore_on_shutdown = (bus->levels == 2); # endif if (ignore_on_shutdown && (state == XenbusStateClosing)) xenbus_frontend_closed(dev); return; } #endif if (drv->otherend_changed) drv->otherend_changed(dev, state); }
static void xenkbd_backend_changed(struct xenbus_device *dev, enum xenbus_state backend_state) { struct xenkbd_info *info = dev_get_drvdata(&dev->dev); int val; switch (backend_state) { case XenbusStateInitialising: case XenbusStateInitialised: case XenbusStateUnknown: case XenbusStateClosed: break; case XenbusStateInitWait: InitWait: xenbus_switch_state(dev, XenbusStateConnected); break; case XenbusStateConnected: /* * Work around xenbus race condition: If backend goes * through InitWait to Connected fast enough, we can * get Connected twice here. */ if (dev->state != XenbusStateConnected) goto InitWait; /* no InitWait seen yet, fudge it */ /* Set input abs params to match backend screen res */ if (xenbus_scanf(XBT_NIL, info->xbdev->otherend, "width", "%d", &val) > 0) input_set_abs_params(info->ptr, ABS_X, 0, val, 0, 0); if (xenbus_scanf(XBT_NIL, info->xbdev->otherend, "height", "%d", &val) > 0) input_set_abs_params(info->ptr, ABS_Y, 0, val, 0, 0); break; case XenbusStateClosing: xenbus_frontend_closed(dev); break; } }
static void otherend_changed(struct xenbus_watch *watch, const char **vec, unsigned int len) { struct xenbus_device *dev = container_of(watch, struct xenbus_device, otherend_watch); struct xenbus_driver *drv = to_xenbus_driver(dev->dev.driver); enum xenbus_state state; /* Protect us against watches firing on old details when the otherend details change, say immediately after a resume. */ if (!dev->otherend || strncmp(dev->otherend, vec[XS_WATCH_PATH], strlen(dev->otherend))) { dev_dbg(&dev->dev, "Ignoring watch at %s\n", vec[XS_WATCH_PATH]); return; } state = xenbus_read_driver_state(dev->otherend); dev_dbg(&dev->dev, "state is %d, (%s), %s, %s\n", state, xenbus_strstate(state), dev->otherend_watch.node, vec[XS_WATCH_PATH]); /* * Ignore xenbus transitions during shutdown. This prevents us doing * work that can fail e.g., when the rootfs is gone. */ if (system_state > SYSTEM_RUNNING) { struct xen_bus_type *bus = bus; bus = container_of(dev->dev.bus, struct xen_bus_type, bus); /* If we're frontend, drive the state machine to Closed. */ /* This should cause the backend to release our resources. */ if ((bus == &xenbus_frontend) && (state == XenbusStateClosing)) xenbus_frontend_closed(dev); return; } if (drv->otherend_changed) drv->otherend_changed(dev, state); }
static void omx_xenfront_backend_changed(struct xenbus_device *dev, enum xenbus_state backend_state) { struct omx_xenfront_info *fe = dev_get_drvdata(&dev->dev); int ret = 0; dprintk_in(); dprintk_deb("backend state %s\n", xenbus_strstate(backend_state)); switch (backend_state) { case XenbusStateInitialising: case XenbusStateInitWait: break; case XenbusStateInitialised: ret = talk_to_backend(dev, fe); if (ret) { printk_err("Error trying to talk to backend" ", ret=%d\n", ret); //kfree(info); } break; case XenbusStateReconfiguring: case XenbusStateReconfigured: case XenbusStateUnknown: case XenbusStateClosed: break; case XenbusStateConnected: if (dev->state == XenbusStateConnected) break; omx_xenfront_connect(fe); break; case XenbusStateClosing: dprintk_deb("Closing Xenbus\n"); xenbus_frontend_closed(dev); break; } dprintk_out(); return; }
void xenbus_otherend_changed(struct xenbus_watch *watch, const char **vec, unsigned int len, int ignore_on_shutdown) { struct xenbus_device *dev = container_of(watch, struct xenbus_device, otherend_watch); struct xenbus_driver *drv = to_xenbus_driver(dev->dev.driver); enum xenbus_state state; /* Protect us against watches firing on old details when the otherend details change, say immediately after a resume. */ if (!dev->otherend || strncmp(dev->otherend, vec[XS_WATCH_PATH], strlen(dev->otherend))) { dev_dbg(&dev->dev, "Ignoring watch at %s\n", vec[XS_WATCH_PATH]); return; } state = xenbus_read_driver_state(dev->otherend); dev_dbg(&dev->dev, "state is %d, (%s), %s, %s\n", state, xenbus_strstate(state), dev->otherend_watch.node, vec[XS_WATCH_PATH]); /* * Ignore xenbus transitions during shutdown. This prevents us doing * work that can fail e.g., when the rootfs is gone. */ if (system_state > SYSTEM_RUNNING) { if (ignore_on_shutdown && (state == XenbusStateClosing)) xenbus_frontend_closed(dev); return; } if (drv->otherend_changed) drv->otherend_changed(dev, state); }
static void scsifront_free(struct vscsifrnt_info *info) { struct Scsi_Host *host = info->host; #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,14) if (host->shost_state != SHOST_DEL) { #else if (!test_bit(SHOST_DEL, &host->shost_state)) { #endif scsi_remove_host(info->host); } if (info->ring_ref != GRANT_INVALID_REF) { gnttab_end_foreign_access(info->ring_ref, (unsigned long)info->ring.sring); info->ring_ref = GRANT_INVALID_REF; info->ring.sring = NULL; } if (info->irq) unbind_from_irqhandler(info->irq, info); info->irq = 0; scsi_host_put(info->host); } static int scsifront_alloc_ring(struct vscsifrnt_info *info) { struct xenbus_device *dev = info->dev; struct vscsiif_sring *sring; int err = -ENOMEM; info->ring_ref = GRANT_INVALID_REF; /***** Frontend to Backend ring start *****/ sring = (struct vscsiif_sring *) __get_free_page(GFP_KERNEL); if (!sring) { xenbus_dev_fatal(dev, err, "fail to allocate shared ring (Front to Back)"); return err; } SHARED_RING_INIT(sring); FRONT_RING_INIT(&info->ring, sring, PAGE_SIZE); err = xenbus_grant_ring(dev, virt_to_mfn(sring)); if (err < 0) { free_page((unsigned long) sring); info->ring.sring = NULL; xenbus_dev_fatal(dev, err, "fail to grant shared ring (Front to Back)"); goto free_sring; } info->ring_ref = err; err = bind_listening_port_to_irqhandler( dev->otherend_id, scsifront_intr, SA_SAMPLE_RANDOM, "scsifront", info); if (err <= 0) { xenbus_dev_fatal(dev, err, "bind_listening_port_to_irqhandler"); goto free_sring; } info->irq = err; return 0; /* free resource */ free_sring: scsifront_free(info); return err; } static int scsifront_init_ring(struct vscsifrnt_info *info) { struct xenbus_device *dev = info->dev; struct xenbus_transaction xbt; int err; DPRINTK("%s\n",__FUNCTION__); err = scsifront_alloc_ring(info); if (err) return err; DPRINTK("%u %u\n", info->ring_ref, info->evtchn); again: err = xenbus_transaction_start(&xbt); if (err) { xenbus_dev_fatal(dev, err, "starting transaction"); } err = xenbus_printf(xbt, dev->nodename, "ring-ref", "%u", info->ring_ref); if (err) { xenbus_dev_fatal(dev, err, "%s", "writing ring-ref"); goto fail; } err = xenbus_printf(xbt, dev->nodename, "event-channel", "%u", irq_to_evtchn_port(info->irq)); if (err) { xenbus_dev_fatal(dev, err, "%s", "writing event-channel"); goto fail; } err = xenbus_transaction_end(xbt, 0); if (err) { if (err == -EAGAIN) goto again; xenbus_dev_fatal(dev, err, "completing transaction"); goto free_sring; } return 0; fail: xenbus_transaction_end(xbt, 1); free_sring: /* free resource */ scsifront_free(info); return err; } static int scsifront_probe(struct xenbus_device *dev, const struct xenbus_device_id *id) { struct vscsifrnt_info *info; struct Scsi_Host *host; int i, err = -ENOMEM; char name[DEFAULT_TASK_COMM_LEN]; host = scsi_host_alloc(&scsifront_sht, sizeof(*info)); if (!host) { xenbus_dev_fatal(dev, err, "fail to allocate scsi host"); return err; } info = (struct vscsifrnt_info *) host->hostdata; info->host = host; dev->dev.driver_data = info; info->dev = dev; for (i = 0; i < VSCSIIF_MAX_REQS; i++) { info->shadow[i].next_free = i + 1; init_waitqueue_head(&(info->shadow[i].wq_reset)); info->shadow[i].wait_reset = 0; } info->shadow[VSCSIIF_MAX_REQS - 1].next_free = 0x0fff; err = scsifront_init_ring(info); if (err) { scsi_host_put(host); return err; } init_waitqueue_head(&info->wq); spin_lock_init(&info->io_lock); spin_lock_init(&info->shadow_lock); snprintf(name, DEFAULT_TASK_COMM_LEN, "vscsiif.%d", info->host->host_no); info->kthread = kthread_run(scsifront_schedule, info, name); if (IS_ERR(info->kthread)) { err = PTR_ERR(info->kthread); info->kthread = NULL; printk(KERN_ERR "scsifront: kthread start err %d\n", err); goto free_sring; } host->max_id = VSCSIIF_MAX_TARGET; host->max_channel = 0; host->max_lun = VSCSIIF_MAX_LUN; host->max_sectors = (VSCSIIF_SG_TABLESIZE - 1) * PAGE_SIZE / 512; err = scsi_add_host(host, &dev->dev); if (err) { printk(KERN_ERR "scsifront: fail to add scsi host %d\n", err); goto free_sring; } xenbus_switch_state(dev, XenbusStateInitialised); return 0; free_sring: /* free resource */ scsifront_free(info); return err; } static int scsifront_remove(struct xenbus_device *dev) { struct vscsifrnt_info *info = dev->dev.driver_data; DPRINTK("%s: %s removed\n",__FUNCTION__ ,dev->nodename); if (info->kthread) { kthread_stop(info->kthread); info->kthread = NULL; } scsifront_free(info); return 0; } static int scsifront_disconnect(struct vscsifrnt_info *info) { struct xenbus_device *dev = info->dev; struct Scsi_Host *host = info->host; DPRINTK("%s: %s disconnect\n",__FUNCTION__ ,dev->nodename); /* When this function is executed, all devices of Frontend have been deleted. Therefore, it need not block I/O before remove_host. */ scsi_remove_host(host); xenbus_frontend_closed(dev); return 0; } #define VSCSIFRONT_OP_ADD_LUN 1 #define VSCSIFRONT_OP_DEL_LUN 2 static void scsifront_do_lun_hotplug(struct vscsifrnt_info *info, int op) { struct xenbus_device *dev = info->dev; int i, err = 0; char str[64], state_str[64]; char **dir; unsigned int dir_n = 0; unsigned int device_state; unsigned int hst, chn, tgt, lun; struct scsi_device *sdev; dir = xenbus_directory(XBT_NIL, dev->otherend, "vscsi-devs", &dir_n); if (IS_ERR(dir)) return; for (i = 0; i < dir_n; i++) { /* read status */ snprintf(str, sizeof(str), "vscsi-devs/%s/state", dir[i]); err = xenbus_scanf(XBT_NIL, dev->otherend, str, "%u", &device_state); if (XENBUS_EXIST_ERR(err)) continue; /* virtual SCSI device */ snprintf(str, sizeof(str), "vscsi-devs/%s/v-dev", dir[i]); err = xenbus_scanf(XBT_NIL, dev->otherend, str, "%u:%u:%u:%u", &hst, &chn, &tgt, &lun); if (XENBUS_EXIST_ERR(err)) continue; /* front device state path */ snprintf(state_str, sizeof(state_str), "vscsi-devs/%s/state", dir[i]); switch (op) { case VSCSIFRONT_OP_ADD_LUN: if (device_state == XenbusStateInitialised) { sdev = scsi_device_lookup(info->host, chn, tgt, lun); if (sdev) { printk(KERN_ERR "scsifront: Device already in use.\n"); scsi_device_put(sdev); xenbus_printf(XBT_NIL, dev->nodename, state_str, "%d", XenbusStateClosed); } else { scsi_add_device(info->host, chn, tgt, lun); xenbus_printf(XBT_NIL, dev->nodename, state_str, "%d", XenbusStateConnected); } } break; case VSCSIFRONT_OP_DEL_LUN: if (device_state == XenbusStateClosing) { sdev = scsi_device_lookup(info->host, chn, tgt, lun); if (sdev) { scsi_remove_device(sdev); scsi_device_put(sdev); xenbus_printf(XBT_NIL, dev->nodename, state_str, "%d", XenbusStateClosed); } } break; default: break; } } kfree(dir); return; } static void scsifront_backend_changed(struct xenbus_device *dev, enum xenbus_state backend_state) { struct vscsifrnt_info *info = dev->dev.driver_data; DPRINTK("%p %u %u\n", dev, dev->state, backend_state); switch (backend_state) { case XenbusStateUnknown: case XenbusStateInitialising: case XenbusStateInitWait: case XenbusStateClosed: break; case XenbusStateInitialised: break; case XenbusStateConnected: if (xenbus_read_driver_state(dev->nodename) == XenbusStateInitialised) { scsifront_do_lun_hotplug(info, VSCSIFRONT_OP_ADD_LUN); } if (dev->state == XenbusStateConnected) break; xenbus_switch_state(dev, XenbusStateConnected); break; case XenbusStateClosing: scsifront_disconnect(info); break; case XenbusStateReconfiguring: scsifront_do_lun_hotplug(info, VSCSIFRONT_OP_DEL_LUN); xenbus_switch_state(dev, XenbusStateReconfiguring); break; case XenbusStateReconfigured: scsifront_do_lun_hotplug(info, VSCSIFRONT_OP_ADD_LUN); xenbus_switch_state(dev, XenbusStateConnected); break; } } static struct xenbus_device_id scsifront_ids[] = { { "vscsi" }, { "" } }; MODULE_ALIAS("xen:vscsi"); static struct xenbus_driver scsifront_driver = { .name = "vscsi", .owner = THIS_MODULE, .ids = scsifront_ids, .probe = scsifront_probe, .remove = scsifront_remove, /* .resume = scsifront_resume, */ .otherend_changed = scsifront_backend_changed, }; int scsifront_xenbus_init(void) { return xenbus_register_frontend(&scsifront_driver); } void scsifront_xenbus_unregister(void) { xenbus_unregister_driver(&scsifront_driver); }