struct fbfront_dev *init_fbfront(char *_nodename, unsigned long *mfns, int width, int height, int depth, int stride, int n) { xenbus_transaction_t xbt; char* err; char* message=NULL; struct xenfb_page *s; int retry=0; char* msg=NULL; int i, j; struct fbfront_dev *dev; int max_pd; unsigned long mapped; char* nodename = _nodename ? _nodename : "device/vfb/0"; char path[strlen(nodename) + strlen("/backend-id") + 1]; printk("******************* FBFRONT for %s **********\n\n\n", nodename); dev = malloc(sizeof(*dev)); memset(dev, 0, sizeof(*dev)); dev->nodename = strdup(nodename); #ifdef HAVE_LIBC dev->fd = -1; #endif snprintf(path, sizeof(path), "%s/backend-id", nodename); dev->dom = xenbus_read_integer(path); evtchn_alloc_unbound(dev->dom, fbfront_handler, dev, &dev->evtchn); dev->page = s = (struct xenfb_page*) alloc_page(); memset(s,0,PAGE_SIZE); s->in_cons = s->in_prod = 0; s->out_cons = s->out_prod = 0; dev->width = s->width = width; dev->height = s->height = height; dev->depth = s->depth = depth; dev->stride = s->line_length = stride; dev->mem_length = s->mem_length = n * PAGE_SIZE; dev->offset = 0; dev->events = NULL; max_pd = sizeof(s->pd) / sizeof(s->pd[0]); mapped = 0; for (i = 0; mapped < n && i < max_pd; i++) { unsigned long *pd = (unsigned long *) alloc_page(); for (j = 0; mapped < n && j < PAGE_SIZE / sizeof(unsigned long); j++) pd[j] = mfns[mapped++]; for ( ; j < PAGE_SIZE / sizeof(unsigned long); j++) pd[j] = 0; s->pd[i] = virt_to_mfn(pd); } for ( ; i < max_pd; i++) s->pd[i] = 0; again: err = xenbus_transaction_start(&xbt); if (err) { printk("starting transaction\n"); free(err); } err = xenbus_printf(xbt, nodename, "page-ref","%lu", virt_to_mfn(s)); if (err) { message = "writing page-ref"; goto abort_transaction; } err = xenbus_printf(xbt, nodename, "event-channel", "%u", dev->evtchn); if (err) { message = "writing event-channel"; goto abort_transaction; } err = xenbus_printf(xbt, nodename, "protocol", "%s", XEN_IO_PROTO_ABI_NATIVE); if (err) { message = "writing event-channel"; goto abort_transaction; } err = xenbus_printf(xbt, nodename, "feature-update", "1"); if (err) { message = "writing event-channel"; goto abort_transaction; } snprintf(path, sizeof(path), "%s/state", nodename); err = xenbus_switch_state(xbt, path, XenbusStateInitialised); if (err) { message = "switching state"; goto abort_transaction; } err = xenbus_transaction_end(xbt, 0, &retry); free(err); if (retry) { goto again; printk("completing transaction\n"); } goto done; abort_transaction: free(err); err = xenbus_transaction_end(xbt, 1, &retry); printk("Abort transaction %s\n", message); goto error; done: snprintf(path, sizeof(path), "%s/backend", nodename); msg = xenbus_read(XBT_NIL, path, &dev->backend); if (msg) { printk("Error %s when reading the backend path %s\n", msg, path); goto error; } printk("backend at %s\n", dev->backend); { XenbusState state; char path[strlen(dev->backend) + strlen("/request-update") + 1]; char frontpath[strlen(nodename) + strlen("/state") + 1]; snprintf(path, sizeof(path), "%s/state", dev->backend); xenbus_watch_path_token(XBT_NIL, path, path, &dev->events); err = NULL; state = xenbus_read_integer(path); while (err == NULL && state < XenbusStateConnected) err = xenbus_wait_for_state_change(path, &state, &dev->events); if (state != XenbusStateConnected) { printk("backend not available, state=%d\n", state); free(err); err = xenbus_unwatch_path_token(XBT_NIL, path, path); goto error; } printk("%s connected\n", dev->backend); snprintf(path, sizeof(path), "%s/request-update", dev->backend); dev->request_update = xenbus_read_integer(path); snprintf(frontpath, sizeof(frontpath), "%s/state", nodename); if ((err = xenbus_switch_state(XBT_NIL, frontpath, XenbusStateConnected)) != NULL) { printk("error switching state: %s\n", err); free(err); err = xenbus_unwatch_path_token(XBT_NIL, path, path); goto error; } } unmask_evtchn(dev->evtchn); printk("************************** FBFRONT\n"); return dev; error: free(msg); free(err); free_fbfront(dev); return NULL; }
static inline int connect_frontend(vbd_t *device) { int err = 0; xs_transaction_t xst = XBT_NULL; bool abort_transaction = false; ASSERT(device); ASSERT(device->cdrom != -1); ASSERT(device->mode != -1); do { if (!(xst = xs_transaction_start(device->backend->xs))) { err = errno; WARN(device, "failed to start transaction: %s\n", strerror(err)); goto out; } abort_transaction = true; /* * FIXME blkback writes discard-granularity, discard-alignment, * discard-secure, feature-discard, feature-barrier but we don't. */ /* * Write the number of sectors, sector size, and info to the * back-end path in XenStore so that the front-end creates a VBD * with the appropriate characteristics. */ if ((err = tapback_device_printf(device, xst, "sector-size", true, "%u", device->sector_size))) { WARN(device, "failed to write sector-size: %s\n", strerror(err)); break; } if ((err = tapback_device_printf(device, xst, "sectors", true, "%llu", device->sectors))) { WARN(device, "failed to write sectors: %s\n", strerror(err)); break; } if ((err = tapback_device_printf(device, xst, "info", true, "%u", device->info))) { WARN(device, "failed to write info: %s\n", strerror(err)); break; } abort_transaction = false; if (!xs_transaction_end(device->backend->xs, xst, 0)) { err = errno; ASSERT(err); } } while (err == EAGAIN); if (abort_transaction) { if (!xs_transaction_end(device->backend->xs, xst, 1)) { int err2 = errno; WARN(device, "failed to abort transaction: %s\n", strerror(err2)); } goto out; } if (err) { WARN(device, "failed to end transaction: %s\n", strerror(err)); goto out; } err = xenbus_switch_state(device, XenbusStateConnected); if (err) WARN(device, "failed to switch back-end state to connected: %s\n", strerror(err)); out: return err; }
/** * Entry point to this code when a new device is created. Allocate the basic * structures and switch to InitWait. */ static int netback_probe(struct xenbus_device *dev, const struct xenbus_device_id *id) { const char *message; struct xenbus_transaction xbt; int err; struct backend_info *be = kzalloc(sizeof(struct backend_info), GFP_KERNEL); if (!be) { xenbus_dev_fatal(dev, -ENOMEM, "allocating backend structure"); return -ENOMEM; } be->dev = dev; dev->dev.driver_data = be; do { err = xenbus_transaction_start(&xbt); if (err) { xenbus_dev_fatal(dev, err, "starting transaction"); goto fail; } err = xenbus_printf(xbt, dev->nodename, "feature-sg", "%d", 1); if (err) { message = "writing feature-sg"; goto abort_transaction; } err = xenbus_printf(xbt, dev->nodename, "feature-gso-tcpv4", "%d", 1); if (err) { message = "writing feature-gso-tcpv4"; goto abort_transaction; } err = xenbus_printf(xbt, dev->nodename, "feature-rx-copy", "%d", 1); if (err) { message = "writing feature-copying"; goto abort_transaction; } err = xenbus_transaction_end(xbt, 0); } while (err == -EAGAIN); if (err) { xenbus_dev_fatal(dev, err, "completing transaction"); goto fail; } err = xenbus_switch_state(dev, XenbusStateInitWait); if (err) goto fail; /* This kicks hotplug scripts, so do it immediately. */ backend_create_netif(be); return 0; abort_transaction: xenbus_transaction_end(xbt, 1); xenbus_dev_fatal(dev, err, "%s", message); fail: DPRINTK("failed"); netback_remove(dev); return err; }
/** * Entry point to this code when a new device is created. Allocate the basic * structures and switch to InitWait. */ static int netback_probe(struct xenbus_device *dev, const struct xenbus_device_id *id) { const char *message; struct xenbus_transaction xbt; int err; int sg; struct backend_info *be = kzalloc(sizeof(struct backend_info), GFP_KERNEL); if (!be) { xenbus_dev_fatal(dev, -ENOMEM, "allocating backend structure"); return -ENOMEM; } be->dev = dev; dev_set_drvdata(&dev->dev, be); sg = 1; do { err = xenbus_transaction_start(&xbt); if (err) { xenbus_dev_fatal(dev, err, "starting transaction"); goto fail; } err = xenbus_printf(xbt, dev->nodename, "feature-sg", "%d", sg); if (err) { message = "writing feature-sg"; goto abort_transaction; } err = xenbus_printf(xbt, dev->nodename, "feature-gso-tcpv4", "%d", sg); if (err) { message = "writing feature-gso-tcpv4"; goto abort_transaction; } /* We support rx-copy path. */ err = xenbus_printf(xbt, dev->nodename, "feature-rx-copy", "%d", 1); if (err) { message = "writing feature-rx-copy"; goto abort_transaction; } /* * We don't support rx-flip path (except old guests who don't * grok this feature flag). */ err = xenbus_printf(xbt, dev->nodename, "feature-rx-flip", "%d", 0); if (err) { message = "writing feature-rx-flip"; goto abort_transaction; } err = xenbus_transaction_end(xbt, 0); } while (err == -EAGAIN); if (err) { xenbus_dev_fatal(dev, err, "completing transaction"); goto fail; } err = xenbus_switch_state(dev, XenbusStateInitWait); if (err) goto fail; /* This kicks hotplug scripts, so do it immediately. */ backend_create_xenvif(be); return 0; abort_transaction: xenbus_transaction_end(xbt, 1); xenbus_dev_fatal(dev, err, "%s", message); fail: pr_debug("failed"); netback_remove(dev); return err; }
static int pcifront_detach_devices(struct pcifront_device *pdev) { int err = 0; int i, num_devs; unsigned int domain, bus, slot, func; struct pci_bus *pci_bus; struct pci_dev *pci_dev; char str[64]; spin_lock(&pdev->dev_lock); if (xenbus_read_driver_state(pdev->xdev->nodename) != XenbusStateConnected) goto out; err = xenbus_scanf(XBT_NIL, pdev->xdev->otherend, "num_devs", "%d", &num_devs); if (err != 1) { if (err >= 0) err = -EINVAL; xenbus_dev_fatal(pdev->xdev, err, "Error reading number of PCI devices"); goto out; } /* Find devices being detached and remove them. */ for (i = 0; i < num_devs; i++) { int l, state; l = snprintf(str, sizeof(str), "state-%d", i); if (unlikely(l >= (sizeof(str) - 1))) { err = -ENOMEM; goto out; } err = xenbus_scanf(XBT_NIL, pdev->xdev->otherend, str, "%d", &state); if (err != 1) state = XenbusStateUnknown; if (state != XenbusStateClosing) continue; /* Remove device. */ l = snprintf(str, sizeof(str), "vdev-%d", i); if (unlikely(l >= (sizeof(str) - 1))) { err = -ENOMEM; goto out; } err = xenbus_scanf(XBT_NIL, pdev->xdev->otherend, str, "%x:%x:%x.%x", &domain, &bus, &slot, &func); if (err != 4) { if (err >= 0) err = -EINVAL; xenbus_dev_fatal(pdev->xdev, err, "Error reading PCI device %d", i); goto out; } pci_bus = pci_find_bus(domain, bus); if(!pci_bus) { dev_dbg(&pdev->xdev->dev, "Cannot get bus %04x:%02x\n", domain, bus); continue; } pci_dev = pci_get_slot(pci_bus, PCI_DEVFN(slot, func)); if(!pci_dev) { dev_dbg(&pdev->xdev->dev, "Cannot get PCI device %04x:%02x:%02x.%02x\n", domain, bus, slot, func); continue; } pci_remove_bus_device(pci_dev); pci_dev_put(pci_dev); dev_dbg(&pdev->xdev->dev, "PCI device %04x:%02x:%02x.%02x removed.\n", domain, bus, slot, func); } err = xenbus_switch_state(pdev->xdev, XenbusStateReconfiguring); out: spin_unlock(&pdev->dev_lock); return err; }
int xenbus_frontend_closed(struct xenbus_device *dev) { xenbus_switch_state(dev, XenbusStateClosed); complete(&dev->down); return 0; }
struct blkfront_dev *blkfront_init(char *_nodename, struct blkfront_info *info) { xenbus_transaction_t xbt; char* err; char* message=NULL; struct blkif_sring *s; int retry=0; char* msg = NULL; char* c; char* nodename = _nodename ? _nodename : "device/vbd/768"; struct blkfront_dev *dev; char path[strlen(nodename) + 1 + 10 + 1]; dev = malloc(sizeof(*dev)); memset(dev, 0, sizeof(*dev)); dev->nodename = strdup(nodename); snprintf(path, sizeof(path), "%s/backend-id", nodename); dev->dom = xenbus_read_integer(path); minios_evtchn_alloc_unbound(dev->dom, blkfront_handler, dev, &dev->evtchn); s = (struct blkif_sring*) minios_alloc_page(); memset(s,0,PAGE_SIZE); SHARED_RING_INIT(s); FRONT_RING_INIT(&dev->ring, s, PAGE_SIZE); dev->ring_ref = gnttab_grant_access(dev->dom,virt_to_mfn(s),0); xenbus_event_queue_init(&dev->events); again: err = xenbus_transaction_start(&xbt); if (err) { minios_printk("starting transaction\n"); free(err); } err = xenbus_printf(xbt, nodename, "ring-ref","%u", dev->ring_ref); if (err) { message = "writing ring-ref"; goto abort_transaction; } err = xenbus_printf(xbt, nodename, "event-channel", "%u", dev->evtchn); if (err) { message = "writing event-channel"; goto abort_transaction; } err = xenbus_printf(xbt, nodename, "protocol", "%s", XEN_IO_PROTO_ABI_NATIVE); if (err) { message = "writing protocol"; goto abort_transaction; } snprintf(path, sizeof(path), "%s/state", nodename); err = xenbus_switch_state(xbt, path, XenbusStateConnected); if (err) { message = "switching state"; goto abort_transaction; } err = xenbus_transaction_end(xbt, 0, &retry); if (err) free(err); if (retry) { goto again; minios_printk("completing transaction\n"); } goto done; abort_transaction: free(err); err = xenbus_transaction_end(xbt, 1, &retry); minios_printk("Abort transaction %s\n", message); goto error; done: snprintf(path, sizeof(path), "%s/backend", nodename); msg = xenbus_read(XBT_NIL, path, &dev->backend); if (msg) { minios_printk("Error %s when reading the backend path %s\n", msg, path); goto error; } minios_printk("blkfront: node=%s backend=%s\n", nodename, dev->backend); dev->handle = strtoul(strrchr(nodename, '/')+1, NULL, 10); { XenbusState state; char path[strlen(dev->backend) + 1 + 19 + 1]; snprintf(path, sizeof(path), "%s/mode", dev->backend); msg = xenbus_read(XBT_NIL, path, &c); if (msg) { minios_printk("Error %s when reading the mode\n", msg); goto error; } if (*c == 'w') dev->info.mode = O_RDWR; else dev->info.mode = O_RDONLY; free(c); snprintf(path, sizeof(path), "%s/state", dev->backend); xenbus_watch_path_token(XBT_NIL, path, path, &dev->events); msg = NULL; state = xenbus_read_integer(path); while (msg == NULL && state < XenbusStateConnected) msg = xenbus_wait_for_state_change(path, &state, &dev->events); if (msg != NULL || state != XenbusStateConnected) { minios_printk("backend not available, state=%d\n", state); xenbus_unwatch_path_token(XBT_NIL, path, path); goto error; } snprintf(path, sizeof(path), "%s/info", dev->backend); dev->info.info = xenbus_read_integer(path); snprintf(path, sizeof(path), "%s/sectors", dev->backend); // FIXME: read_integer returns an int, so disk size limited to 1TB for now dev->info.sectors = xenbus_read_integer(path); snprintf(path, sizeof(path), "%s/sector-size", dev->backend); dev->info.sector_size = xenbus_read_integer(path); snprintf(path, sizeof(path), "%s/feature-barrier", dev->backend); dev->info.barrier = xenbus_read_integer(path); snprintf(path, sizeof(path), "%s/feature-flush-cache", dev->backend); dev->info.flush = xenbus_read_integer(path); *info = dev->info; } minios_unmask_evtchn(dev->evtchn); minios_printk("blkfront: %u sectors\n", dev->info.sectors); return dev; error: free(msg); free(err); free_blkfront(dev); return NULL; }
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, IRQF_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_set_drvdata(&dev->dev, 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_get_drvdata(&dev->dev); 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_get_drvdata(&dev->dev); 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" }, { "" } }; static struct xenbus_driver scsifront_driver = { .name = "vscsi", .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); }
struct pcifront_dev *init_pcifront(char *_nodename) { xenbus_transaction_t xbt; char* err; char* message=NULL; int retry=0; char* msg = NULL; char* nodename = _nodename ? _nodename : "device/pci/0"; int dom; struct pcifront_dev *dev; char path[strlen(nodename) + strlen("/backend-id") + 1]; if (!_nodename && pcidev) return pcidev; printk("******************* PCIFRONT for %s **********\n\n\n", nodename); snprintf(path, sizeof(path), "%s/backend-id", nodename); dom = xenbus_read_integer(path); if (dom == -1) { printk("no backend\n"); return NULL; } dev = malloc(sizeof(*dev)); memset(dev, 0, sizeof(*dev)); dev->nodename = strdup(nodename); dev->dom = dom; evtchn_alloc_unbound(dev->dom, pcifront_handler, dev, &dev->evtchn); dev->info = (struct xen_pci_sharedinfo*) alloc_page(); memset(dev->info,0,PAGE_SIZE); dev->info_ref = gnttab_grant_access(dev->dom,virt_to_mfn(dev->info),0); dev->events = NULL; again: err = xenbus_transaction_start(&xbt); if (err) { printk("starting transaction\n"); free(err); } err = xenbus_printf(xbt, nodename, "pci-op-ref","%u", dev->info_ref); if (err) { message = "writing pci-op-ref"; goto abort_transaction; } err = xenbus_printf(xbt, nodename, "event-channel", "%u", dev->evtchn); if (err) { message = "writing event-channel"; goto abort_transaction; } err = xenbus_printf(xbt, nodename, "magic", XEN_PCI_MAGIC); if (err) { message = "writing magic"; goto abort_transaction; } snprintf(path, sizeof(path), "%s/state", nodename); err = xenbus_switch_state(xbt, path, XenbusStateInitialised); if (err) { message = "switching state"; goto abort_transaction; } err = xenbus_transaction_end(xbt, 0, &retry); free(err); if (retry) { goto again; printk("completing transaction\n"); } goto done; abort_transaction: free(err); err = xenbus_transaction_end(xbt, 1, &retry); printk("Abort transaction %s\n", message); goto error; done: snprintf(path, sizeof(path), "%s/backend", nodename); msg = xenbus_read(XBT_NIL, path, &dev->backend); if (msg) { printk("Error %s when reading the backend path %s\n", msg, path); goto error; } printk("backend at %s\n", dev->backend); { char path[strlen(dev->backend) + strlen("/state") + 1]; char frontpath[strlen(nodename) + strlen("/state") + 1]; XenbusState state; snprintf(path, sizeof(path), "%s/state", dev->backend); xenbus_watch_path_token(XBT_NIL, path, path, &dev->events); err = NULL; state = xenbus_read_integer(path); while (err == NULL && state < XenbusStateConnected) err = xenbus_wait_for_state_change(path, &state, &dev->events); if (state != XenbusStateConnected) { printk("backend not avalable, state=%d\n", state); free(err); err = xenbus_unwatch_path_token(XBT_NIL, path, path); goto error; } snprintf(frontpath, sizeof(frontpath), "%s/state", nodename); if ((err = xenbus_switch_state(XBT_NIL, frontpath, XenbusStateConnected)) != NULL) { printk("error switching state %s\n", err); free(err); err = xenbus_unwatch_path_token(XBT_NIL, path, path); goto error; } } unmask_evtchn(dev->evtchn); printk("**************************\n"); if (!_nodename) pcidev = dev; return dev; error: free(msg); free(err); free_pcifront(dev); return NULL; }
struct consfront_dev *init_consfront(char *_nodename) { xenbus_transaction_t xbt; char* err; char* message=NULL; int retry=0; char* msg = NULL; char nodename[256]; char path[256]; static int consfrontends = 3; struct consfront_dev *dev; int res; if (!_nodename) snprintf(nodename, sizeof(nodename), "device/console/%d", consfrontends); else strncpy(nodename, _nodename, sizeof(nodename)); printk("******************* CONSFRONT for %s **********\n\n\n", nodename); consfrontends++; dev = malloc(sizeof(*dev)); memset(dev, 0, sizeof(*dev)); dev->nodename = strdup(nodename); #ifdef HAVE_LIBC dev->fd = -1; #endif snprintf(path, sizeof(path), "%s/backend-id", nodename); if ((res = xenbus_read_integer(path)) < 0) return NULL; else dev->dom = res; evtchn_alloc_unbound(dev->dom, handle_input, dev, &dev->evtchn); dev->ring = (struct xencons_interface *) alloc_page(); memset(dev->ring, 0, PAGE_SIZE); dev->ring_ref = gnttab_grant_access(dev->dom, virt_to_mfn(dev->ring), 0); dev->events = NULL; again: err = xenbus_transaction_start(&xbt); if (err) { printk("starting transaction\n"); free(err); } err = xenbus_printf(xbt, nodename, "ring-ref","%u", dev->ring_ref); if (err) { message = "writing ring-ref"; goto abort_transaction; } err = xenbus_printf(xbt, nodename, "port", "%u", dev->evtchn); if (err) { message = "writing event-channel"; goto abort_transaction; } err = xenbus_printf(xbt, nodename, "protocol", "%s", XEN_IO_PROTO_ABI_NATIVE); if (err) { message = "writing protocol"; goto abort_transaction; } err = xenbus_printf(xbt, nodename, "type", "%s", "ioemu"); if (err) { message = "writing type"; goto abort_transaction; } snprintf(path, sizeof(path), "%s/state", nodename); err = xenbus_switch_state(xbt, path, XenbusStateConnected); if (err) { message = "switching state"; goto abort_transaction; } err = xenbus_transaction_end(xbt, 0, &retry); if (err) free(err); if (retry) { goto again; printk("completing transaction\n"); } goto done; abort_transaction: free(err); err = xenbus_transaction_end(xbt, 1, &retry); printk("Abort transaction %s\n", message); goto error; done: snprintf(path, sizeof(path), "%s/backend", nodename); msg = xenbus_read(XBT_NIL, path, &dev->backend); if (msg) { printk("Error %s when reading the backend path %s\n", msg, path); goto error; } printk("backend at %s\n", dev->backend); { XenbusState state; char path[strlen(dev->backend) + 1 + 19 + 1]; snprintf(path, sizeof(path), "%s/state", dev->backend); xenbus_watch_path_token(XBT_NIL, path, path, &dev->events); msg = NULL; state = xenbus_read_integer(path); while (msg == NULL && state < XenbusStateConnected) msg = xenbus_wait_for_state_change(path, &state, &dev->events); if (msg != NULL || state != XenbusStateConnected) { printk("backend not available, state=%d\n", state); xenbus_unwatch_path_token(XBT_NIL, path, path); goto error; } } unmask_evtchn(dev->evtchn); printk("**************************\n"); return dev; error: free(msg); free(err); free_consfront(dev); return NULL; }
void suspend_netfront(struct netfront_dev *dev) { char* err = NULL, *err2; XenbusState state; char path[strlen(dev->backend) + strlen("/state") + 1]; char nodename[strlen(dev->nodename) + strlen("/request-rx-copy") + 1]; netfrontends--; snprintf(path, sizeof(path), "%s/state", dev->backend); snprintf(nodename, sizeof(nodename), "%s/state", dev->nodename); if ((err = xenbus_switch_state(XBT_NIL, nodename, XenbusStateClosing)) != NULL) { printk("shutdown_netfront: error changing state to %d: %s\n", XenbusStateClosing, err); goto close; } state = xenbus_read_integer(path); while (err == NULL && state < XenbusStateClosing) err = xenbus_wait_for_state_change(path, &state, &dev->events); free(err); if ((err = xenbus_switch_state(XBT_NIL, nodename, XenbusStateClosed)) != NULL) { printk("shutdown_netfront: error changing state to %d: %s\n", XenbusStateClosed, err); goto close; } state = xenbus_read_integer(path); while (state < XenbusStateClosed) { err = xenbus_wait_for_state_change(path, &state, &dev->events); free(err); } if ((err = xenbus_switch_state(XBT_NIL, nodename, XenbusStateInitialising)) != NULL) { printk("shutdown_netfront: error changing state to %d: %s\n", XenbusStateInitialising, err); goto close; } state = xenbus_read_integer(path); while (err == NULL && (state < XenbusStateInitWait || state >= XenbusStateClosed)) err = xenbus_wait_for_state_change(path, &state, &dev->events); close: free(err); err2 = xenbus_unwatch_path_token(XBT_NIL, path, path); free(err2); snprintf(nodename, sizeof(nodename), "%s/tx-ring-ref", dev->nodename); err2 = xenbus_rm(XBT_NIL, nodename); free(err2); snprintf(nodename, sizeof(nodename), "%s/rx-ring-ref", dev->nodename); err2 = xenbus_rm(XBT_NIL, nodename); free(err2); snprintf(nodename, sizeof(nodename), "%s/event-channel", dev->nodename); err2 = xenbus_rm(XBT_NIL, nodename); free(err2); snprintf(nodename, sizeof(nodename), "%s/request-rx-copy", dev->nodename); err2 = xenbus_rm(XBT_NIL, nodename); free(err2); if (!err) free_netfront(dev); }
/** * Connect the OpenXT input device to the corresponding backend. * * @param dev The device to be connected. * @param info The information structure that corresponds to the given device. * * @return int Zero on success, or an error code on failure. */ static int oxtkbd_connect_backend(struct xenbus_device *dev, struct openxt_kbd_info *info) { int ret, evtchn; struct xenbus_transaction xbt; //To communicate with the backend, we'll share a single page of memory //We'll start this process by granting out our "shared page". ret = gnttab_grant_foreign_access(dev->otherend_id, virt_to_mfn(info->page), 0); if (ret < 0) return ret; info->gref = ret; //Next, we'll need to create an event channel we can use to signal that data //has changed in our shared page. ret = xenbus_alloc_evtchn(dev, &evtchn); if (ret) goto error_grant; //Bind our input handler to our event channel-- ensuring we're recieve any //"new data" notifications. ret = bind_evtchn_to_irqhandler(evtchn, input_handler, 0, dev->devicetype, info); if (ret < 0) { xenbus_dev_fatal(dev, ret, "bind_evtchn_to_irqhandler"); goto error_evtchan; } info->irq = ret; again: //Now that we've set up our shared assets, we'll need to communicate them //to the backend. First, we'll start a xenbus transaction, so we can dump //all of our data into the XenStore simultaneously. ret = xenbus_transaction_start(&xbt); if (ret) { xenbus_dev_fatal(dev, ret, "starting transaction"); goto error_irqh; } //Provide a direct reference to the page. This allows backends that want //to use foreign mappings (i.e. legacy backends) to map in the shared page //without touching grants. ret = xenbus_printf(xbt, dev->nodename, "page-ref", "%lu", virt_to_mfn(info->page)); if (ret) goto error_xenbus; //And provide our grant reference. This is the preferred way of getting the //shared page. ret = xenbus_printf(xbt, dev->nodename, "page-gref", "%u", info->gref); if (ret) goto error_xenbus; //Provide the number for our event channel, so the backend can signal //new informatino to us. ret = xenbus_printf(xbt, dev->nodename, "event-channel", "%u", evtchn); if (ret) goto error_xenbus; //Attempt to apply all of our changes at once. ret = xenbus_transaction_end(xbt, 0); //If our transaction failed... if (ret) { //... it may have been because the XenStore was busy. If this is the case, //repeat out transaction until we succeed, or hit an error. if (ret == -EAGAIN) goto again; //Otherwise, we couldn't connect. Bail out! xenbus_dev_fatal(dev, ret, "completing transaction"); goto error_irqh; } //Finally, switch our state to "intialized", hopefully cueing the backend //to connect. xenbus_switch_state(dev, XenbusStateInitialised); return 0; error_xenbus: xenbus_transaction_end(xbt, 1); xenbus_dev_fatal(dev, ret, "writing xenstore"); error_irqh: unbind_from_irqhandler(info->irq, info); info->irq = -1; error_evtchan: xenbus_free_evtchn(dev, evtchn); error_grant: gnttab_end_foreign_access(info->gref, 0, 0UL); info->gref = -1; return ret; }
static int omx_xenfront_probe(struct xenbus_device *dev, const struct xenbus_device_id *id) { struct omx_xenfront_info *fe; struct omx_xenif_sring *sring, *recv_sring; int err = 0; int i = 0; dprintk_in(); dprintk_deb("Frontend Probe Fired!\n"); fe = kzalloc(sizeof(*fe), GFP_KERNEL); dprintk_deb("fe info is @%#llx!\n", (unsigned long long)fe); if (!fe) { xenbus_dev_fatal(dev, -ENOMEM, "allocating info structure"); err = -ENOMEM; goto out; } __omx_xen_frontend = fe; for (i = 0; i < OMX_XEN_MAX_ENDPOINTS; i++) { fe->endpoints[i] = NULL; } fe->requests = kzalloc(OMX_MAX_INFLIGHT_REQUESTS * sizeof(enum frontend_status), GFP_KERNEL); spin_lock_init(&fe->status_lock); fe->xbdev = dev; fe->connected = OMXIF_STATE_DISCONNECTED; init_waitqueue_head(&fe->wq); fe->msg_workq = create_singlethread_workqueue("ReQ_FE"); if (unlikely(!fe->msg_workq)) { printk_err("Couldn't create msg_workq!\n"); err = -ENOMEM; goto out; } INIT_WORK(&fe->msg_workq_task, omx_xenif_interrupt); spin_lock_init(&fe->lock); dprintk_deb("Setting up shared ring\n"); sring = (struct omx_xenif_sring *)get_zeroed_page(GFP_NOIO | __GFP_HIGH); if (!sring) { xenbus_dev_fatal(dev, -ENOMEM, "allocating shared ring"); err = -ENOMEM; goto out; } SHARED_RING_INIT(sring); FRONT_RING_INIT(&fe->ring, sring, PAGE_SIZE); err = xenbus_grant_ring(dev, virt_to_mfn(fe->ring.sring)); if (err < 0) { free_page((unsigned long)sring); fe->ring.sring = NULL; printk_err("Failed to grant ring\n"); goto out; } fe->ring_ref = err; recv_sring = (struct omx_xenif_sring *)get_zeroed_page(GFP_NOIO | __GFP_HIGH); if (!sring) { xenbus_dev_fatal(dev, -ENOMEM, "allocating shared ring"); err = -ENOMEM; goto out; } SHARED_RING_INIT(recv_sring); FRONT_RING_INIT(&fe->recv_ring, recv_sring, PAGE_SIZE); err = xenbus_grant_ring(dev, virt_to_mfn(fe->recv_ring.sring)); if (err < 0) { free_page((unsigned long)recv_sring); fe->recv_ring.sring = NULL; printk_err("Failed to grant recv_ring\n"); goto out; } fe->recv_ring_ref = err; fe->handle = simple_strtoul(strrchr(dev->nodename, '/') + 1, NULL, 0); dprintk_deb("setting handle = %u\n", fe->handle); dev_set_drvdata(&dev->dev, fe); err = 0; //omx_xenfront_dev->info = info; //fe->endpoints = kzalloc(sizeof(struct omx_endpoint*) * OMX_XEN_MAX_ENDPOINTS, GFP_KERNEL); xenbus_switch_state(dev, XenbusStateInitialising); out: dprintk_out(); return err; }
/* caller must clean up in case of errors */ static int setup_ring(struct xenbus_device *dev, struct tpm_private *priv) { struct xenbus_transaction xbt; const char *message = NULL; int rv; priv->shr = (void *)__get_free_page(GFP_KERNEL|__GFP_ZERO); if (!priv->shr) { xenbus_dev_fatal(dev, -ENOMEM, "allocating shared ring"); return -ENOMEM; } rv = xenbus_grant_ring(dev, virt_to_mfn(priv->shr)); if (rv < 0) return rv; priv->ring_ref = rv; rv = xenbus_alloc_evtchn(dev, &priv->evtchn); if (rv) return rv; rv = bind_evtchn_to_irqhandler(priv->evtchn, tpmif_interrupt, 0, "tpmif", priv); if (rv <= 0) { xenbus_dev_fatal(dev, rv, "allocating TPM irq"); return rv; } priv->chip->vendor.irq = rv; again: rv = xenbus_transaction_start(&xbt); if (rv) { xenbus_dev_fatal(dev, rv, "starting transaction"); return rv; } rv = xenbus_printf(xbt, dev->nodename, "ring-ref", "%u", priv->ring_ref); if (rv) { message = "writing ring-ref"; goto abort_transaction; } rv = xenbus_printf(xbt, dev->nodename, "event-channel", "%u", priv->evtchn); if (rv) { message = "writing event-channel"; goto abort_transaction; } rv = xenbus_printf(xbt, dev->nodename, "feature-protocol-v2", "1"); if (rv) { message = "writing feature-protocol-v2"; goto abort_transaction; } rv = xenbus_transaction_end(xbt, 0); if (rv == -EAGAIN) goto again; if (rv) { xenbus_dev_fatal(dev, rv, "completing transaction"); return rv; } xenbus_switch_state(dev, XenbusStateInitialised); return 0; abort_transaction: xenbus_transaction_end(xbt, 1); if (message) xenbus_dev_error(dev, rv, "%s", message); return rv; }
void shutdown_fbfront(struct fbfront_dev *dev) { char* err = NULL, *err2; XenbusState state; char path[strlen(dev->backend) + strlen("/state") + 1]; char nodename[strlen(dev->nodename) + strlen("/feature-update") + 1]; printk("close fb: backend at %s\n",dev->backend); snprintf(path, sizeof(path), "%s/state", dev->backend); snprintf(nodename, sizeof(nodename), "%s/state", dev->nodename); if ((err = xenbus_switch_state(XBT_NIL, nodename, XenbusStateClosing)) != NULL) { printk("shutdown_fbfront: error changing state to %d: %s\n", XenbusStateClosing, err); goto close_fbfront; } state = xenbus_read_integer(path); while (err == NULL && state < XenbusStateClosing) err = xenbus_wait_for_state_change(path, &state, &dev->events); free(err); if ((err = xenbus_switch_state(XBT_NIL, nodename, XenbusStateClosed)) != NULL) { printk("shutdown_fbfront: error changing state to %d: %s\n", XenbusStateClosed, err); goto close_fbfront; } state = xenbus_read_integer(path); if (state < XenbusStateClosed) { err = xenbus_wait_for_state_change(path, &state, &dev->events); free(err); } if ((err = xenbus_switch_state(XBT_NIL, nodename, XenbusStateInitialising)) != NULL) { printk("shutdown_fbfront: error changing state to %d: %s\n", XenbusStateInitialising, err); goto close_fbfront; } state = xenbus_read_integer(path); while (err == NULL && (state < XenbusStateInitWait || state >= XenbusStateClosed)) err = xenbus_wait_for_state_change(path, &state, &dev->events); close_fbfront: free(err); err2 = xenbus_unwatch_path_token(XBT_NIL, path, path); free(err2); snprintf(nodename, sizeof(nodename), "%s/page-ref", dev->nodename); err2 = xenbus_rm(XBT_NIL, nodename); free(err2); snprintf(nodename, sizeof(nodename), "%s/event-channel", dev->nodename); err2 = xenbus_rm(XBT_NIL, nodename); free(err2); snprintf(nodename, sizeof(nodename), "%s/protocol", dev->nodename); err2 = xenbus_rm(XBT_NIL, nodename); free(err2); snprintf(nodename, sizeof(nodename), "%s/feature-update", dev->nodename); err2 = xenbus_rm(XBT_NIL, nodename); free(err2); if (!err) free_fbfront(dev); }
void pcifront_watches(void *opaque) { XenbusState state; char *err = NULL, *msg = NULL; char *be_path, *be_state; char* nodename = opaque ? opaque : "device/pci/0"; char path[strlen(nodename) + 9]; char fe_state[strlen(nodename) + 7]; xenbus_event_queue events = NULL; snprintf(path, sizeof(path), "%s/backend", nodename); snprintf(fe_state, sizeof(fe_state), "%s/state", nodename); while (1) { printk("pcifront_watches: waiting for backend path to appear %s\n", path); xenbus_watch_path_token(XBT_NIL, path, path, &events); while ((err = xenbus_read(XBT_NIL, path, &be_path)) != NULL) { free(err); xenbus_wait_for_watch(&events); } xenbus_unwatch_path_token(XBT_NIL, path, path); printk("pcifront_watches: waiting for backend to get into the right state %s\n", be_path); be_state = (char *) malloc(strlen(be_path) + 7); snprintf(be_state, strlen(be_path) + 7, "%s/state", be_path); xenbus_watch_path_token(XBT_NIL, be_state, be_state, &events); while ((err = xenbus_read(XBT_NIL, be_state, &msg)) != NULL || msg[0] > '4') { free(msg); free(err); xenbus_wait_for_watch(&events); } xenbus_unwatch_path_token(XBT_NIL, be_state, be_state); if (init_pcifront(NULL) == NULL) { free(be_state); free(be_path); continue; } xenbus_watch_path_token(XBT_NIL, be_state, be_state, &events); state = XenbusStateConnected; printk("pcifront_watches: waiting for backend events %s\n", be_state); while ((err = xenbus_wait_for_state_change(be_state, &state, &events)) == NULL && (err = xenbus_read(XBT_NIL, pcidev->backend, &msg)) == NULL) { free(msg); printk("pcifront_watches: backend state changed: %s %d\n", be_state, state); if (state == XenbusStateReconfiguring) { printk("pcifront_watches: writing %s %d\n", fe_state, XenbusStateReconfiguring); if ((err = xenbus_switch_state(XBT_NIL, fe_state, XenbusStateReconfiguring)) != NULL) { printk("pcifront_watches: error changing state to %d: %s\n", XenbusStateReconfiguring, err); if (!strcmp(err, "ENOENT")) { xenbus_write(XBT_NIL, fe_state, "7"); free(err); } } } else if (state == XenbusStateReconfigured) { printk("pcifront_watches: writing %s %d\n", fe_state, XenbusStateConnected); printk("pcifront_watches: changing state to %d\n", XenbusStateConnected); if ((err = xenbus_switch_state(XBT_NIL, fe_state, XenbusStateConnected)) != NULL) { printk("pcifront_watches: error changing state to %d: %s\n", XenbusStateConnected, err); if (!strcmp(err, "ENOENT")) { xenbus_write(XBT_NIL, fe_state, "4"); free(err); } } } else if (state == XenbusStateClosing) break; } if (err) { printk("pcifront_watches: done waiting err=%s\n", err); free(err); } else printk("pcifront_watches: done waiting\n"); err = xenbus_unwatch_path_token(XBT_NIL, be_state, be_state); shutdown_pcifront(pcidev); free(be_state); free(be_path); free(err); pcidev = NULL; } xenbus_unwatch_path_token(XBT_NIL, path, path); }
struct kbdfront_dev *init_kbdfront(char *_nodename, int abs_pointer) { xenbus_transaction_t xbt; char* err; char* message=NULL; struct xenkbd_page *s; int retry=0; char* msg = NULL; char* nodename = _nodename ? _nodename : "device/vkbd/0"; struct kbdfront_dev *dev; char path[strlen(nodename) + strlen("/backend-id") + 1]; printk("******************* KBDFRONT for %s **********\n\n\n", nodename); dev = malloc(sizeof(*dev)); memset(dev, 0, sizeof(*dev)); dev->nodename = strdup(nodename); #ifdef HAVE_LIBC dev->fd = -1; #endif snprintf(path, sizeof(path), "%s/backend-id", nodename); dev->dom = xenbus_read_integer(path); evtchn_alloc_unbound(dev->dom, kbdfront_handler, dev, &dev->evtchn); dev->page = s = (struct xenkbd_page*) alloc_page(); memset(s,0,PAGE_SIZE); dev->events = NULL; s->in_cons = s->in_prod = 0; s->out_cons = s->out_prod = 0; again: err = xenbus_transaction_start(&xbt); if (err) { printk("starting transaction\n"); free(err); } err = xenbus_printf(xbt, nodename, "page-ref","%lu", virt_to_mfn(s)); if (err) { message = "writing page-ref"; goto abort_transaction; } err = xenbus_printf(xbt, nodename, "event-channel", "%u", dev->evtchn); if (err) { message = "writing event-channel"; goto abort_transaction; } if (abs_pointer) { err = xenbus_printf(xbt, nodename, "request-abs-pointer", "1"); if (err) { message = "writing event-channel"; goto abort_transaction; } } snprintf(path, sizeof(path), "%s/state", nodename); err = xenbus_switch_state(xbt, path, XenbusStateInitialised); if (err) { printk("error writing initialized: %s\n", err); free(err); } err = xenbus_transaction_end(xbt, 0, &retry); free(err); if (retry) { goto again; printk("completing transaction\n"); } goto done; abort_transaction: free(err); err = xenbus_transaction_end(xbt, 1, &retry); printk("Abort transaction %s\n", message); goto error; done: snprintf(path, sizeof(path), "%s/backend", nodename); msg = xenbus_read(XBT_NIL, path, &dev->backend); if (msg) { printk("Error %s when reading the backend path %s\n", msg, path); goto error; } printk("backend at %s\n", dev->backend); { XenbusState state; char path[strlen(dev->backend) + strlen("/state") + 1]; char frontpath[strlen(nodename) + strlen("/state") + 1]; snprintf(path, sizeof(path), "%s/state", dev->backend); xenbus_watch_path_token(XBT_NIL, path, path, &dev->events); err = NULL; state = xenbus_read_integer(path); while (err == NULL && state < XenbusStateConnected) err = xenbus_wait_for_state_change(path, &state, &dev->events); if (state != XenbusStateConnected) { printk("backend not available, state=%d\n", state); free(err); err = xenbus_unwatch_path_token(XBT_NIL, path, path); goto error; } printk("%s connected\n", dev->backend); snprintf(frontpath, sizeof(frontpath), "%s/state", nodename); if((err = xenbus_switch_state(XBT_NIL, frontpath, XenbusStateConnected)) != NULL) { printk("error switching state: %s\n", err); free(err); err = xenbus_unwatch_path_token(XBT_NIL, path, path); goto error; } } unmask_evtchn(dev->evtchn); printk("************************** KBDFRONT\n"); return dev; error: free(msg); free(err); free_kbdfront(dev); return NULL; }
static int xen_pcibk_reconfigure(struct xen_pcibk_device *pdev) { int err = 0; int num_devs; int domain, bus, slot, func; int substate; int i, len; char state_str[64]; char dev_str[64]; dev_dbg(&pdev->xdev->dev, "Reconfiguring device ...\n"); mutex_lock(&pdev->dev_lock); /* Make sure we only reconfigure once */ if (xenbus_read_driver_state(pdev->xdev->nodename) != XenbusStateReconfiguring) goto out; err = xenbus_scanf(XBT_NIL, pdev->xdev->nodename, "num_devs", "%d", &num_devs); if (err != 1) { if (err >= 0) err = -EINVAL; xenbus_dev_fatal(pdev->xdev, err, "Error reading number of devices"); goto out; } for (i = 0; i < num_devs; i++) { len = snprintf(state_str, sizeof(state_str), "state-%d", i); if (unlikely(len >= (sizeof(state_str) - 1))) { err = -ENOMEM; xenbus_dev_fatal(pdev->xdev, err, "String overflow while reading " "configuration"); goto out; } err = xenbus_scanf(XBT_NIL, pdev->xdev->nodename, state_str, "%d", &substate); if (err != 1) substate = XenbusStateUnknown; switch (substate) { case XenbusStateInitialising: dev_dbg(&pdev->xdev->dev, "Attaching dev-%d ...\n", i); len = snprintf(dev_str, sizeof(dev_str), "dev-%d", i); if (unlikely(len >= (sizeof(dev_str) - 1))) { err = -ENOMEM; xenbus_dev_fatal(pdev->xdev, err, "String overflow while " "reading configuration"); goto out; } err = xenbus_scanf(XBT_NIL, pdev->xdev->nodename, dev_str, "%x:%x:%x.%x", &domain, &bus, &slot, &func); if (err < 0) { xenbus_dev_fatal(pdev->xdev, err, "Error reading device " "configuration"); goto out; } if (err != 4) { err = -EINVAL; xenbus_dev_fatal(pdev->xdev, err, "Error parsing pci device " "configuration"); goto out; } err = xen_pcibk_export_device(pdev, domain, bus, slot, func, i); if (err) goto out; /* Publish pci roots. */ err = xen_pcibk_publish_pci_roots(pdev, xen_pcibk_publish_pci_root); if (err) { xenbus_dev_fatal(pdev->xdev, err, "Error while publish PCI root" "buses for frontend"); goto out; } err = xenbus_printf(XBT_NIL, pdev->xdev->nodename, state_str, "%d", XenbusStateInitialised); if (err) { xenbus_dev_fatal(pdev->xdev, err, "Error switching substate of " "dev-%d\n", i); goto out; } break; case XenbusStateClosing: dev_dbg(&pdev->xdev->dev, "Detaching dev-%d ...\n", i); len = snprintf(dev_str, sizeof(dev_str), "vdev-%d", i); if (unlikely(len >= (sizeof(dev_str) - 1))) { err = -ENOMEM; xenbus_dev_fatal(pdev->xdev, err, "String overflow while " "reading configuration"); goto out; } err = xenbus_scanf(XBT_NIL, pdev->xdev->nodename, dev_str, "%x:%x:%x.%x", &domain, &bus, &slot, &func); if (err < 0) { xenbus_dev_fatal(pdev->xdev, err, "Error reading device " "configuration"); goto out; } if (err != 4) { err = -EINVAL; xenbus_dev_fatal(pdev->xdev, err, "Error parsing pci device " "configuration"); goto out; } err = xen_pcibk_remove_device(pdev, domain, bus, slot, func); if (err) goto out; /* TODO: If at some point we implement support for pci * root hot-remove on pcifront side, we'll need to * remove unnecessary xenstore nodes of pci roots here. */ break; default: break; } } err = xenbus_switch_state(pdev->xdev, XenbusStateReconfigured); if (err) { xenbus_dev_fatal(pdev->xdev, err, "Error switching to reconfigured state!"); goto out; } out: mutex_unlock(&pdev->dev_lock); return 0; }
struct netfront_dev *init_netfront(char *_nodename, void (*thenetif_rx)(unsigned char* data, int len), unsigned char rawmac[6], char **ip) { xenbus_transaction_t xbt; char* err; char* message=NULL; struct netif_tx_sring *txs; struct netif_rx_sring *rxs; int retry=0; int i; char* msg = NULL; char nodename[256]; char path[256]; struct netfront_dev *dev; static int netfrontends = 0; if (!_nodename) snprintf(nodename, sizeof(nodename), "device/vif/%d", netfrontends); else strncpy(nodename, _nodename, strlen(nodename)); netfrontends++; if (!thenetif_rx) thenetif_rx = netif_rx; printk("************************ NETFRONT for %s **********\n\n\n", nodename); dev = malloc(sizeof(*dev)); memset(dev, 0, sizeof(*dev)); dev->nodename = strdup(nodename); #ifdef HAVE_LIBC dev->fd = -1; #endif printk("net TX ring size %d\n", NET_TX_RING_SIZE); printk("net RX ring size %d\n", NET_RX_RING_SIZE); init_SEMAPHORE(&dev->tx_sem, NET_TX_RING_SIZE); for(i=0;i<NET_TX_RING_SIZE;i++) { add_id_to_freelist(i,dev->tx_freelist); dev->tx_buffers[i].page = NULL; } for(i=0;i<NET_RX_RING_SIZE;i++) { /* TODO: that's a lot of memory */ dev->rx_buffers[i].page = (char*)alloc_page(); } snprintf(path, sizeof(path), "%s/backend-id", nodename); dev->dom = xenbus_read_integer(path); #ifdef HAVE_LIBC if (thenetif_rx == NETIF_SELECT_RX) evtchn_alloc_unbound(dev->dom, netfront_select_handler, dev, &dev->evtchn); else #endif evtchn_alloc_unbound(dev->dom, netfront_handler, dev, &dev->evtchn); txs = (struct netif_tx_sring *) alloc_page(); rxs = (struct netif_rx_sring *) alloc_page(); memset(txs,0,PAGE_SIZE); memset(rxs,0,PAGE_SIZE); SHARED_RING_INIT(txs); SHARED_RING_INIT(rxs); FRONT_RING_INIT(&dev->tx, txs, PAGE_SIZE); FRONT_RING_INIT(&dev->rx, rxs, PAGE_SIZE); dev->tx_ring_ref = gnttab_grant_access(dev->dom,virt_to_mfn(txs),0); dev->rx_ring_ref = gnttab_grant_access(dev->dom,virt_to_mfn(rxs),0); init_rx_buffers(dev); dev->netif_rx = thenetif_rx; dev->events = NULL; again: err = xenbus_transaction_start(&xbt); if (err) { printk("starting transaction\n"); free(err); } err = xenbus_printf(xbt, nodename, "tx-ring-ref","%u", dev->tx_ring_ref); if (err) { message = "writing tx ring-ref"; goto abort_transaction; } err = xenbus_printf(xbt, nodename, "rx-ring-ref","%u", dev->rx_ring_ref); if (err) { message = "writing rx ring-ref"; goto abort_transaction; } err = xenbus_printf(xbt, nodename, "event-channel", "%u", dev->evtchn); if (err) { message = "writing event-channel"; goto abort_transaction; } err = xenbus_printf(xbt, nodename, "request-rx-copy", "%u", 1); if (err) { message = "writing request-rx-copy"; goto abort_transaction; } snprintf(path, sizeof(path), "%s/state", nodename); err = xenbus_switch_state(xbt, path, XenbusStateConnected); if (err) { message = "switching state"; goto abort_transaction; } err = xenbus_transaction_end(xbt, 0, &retry); if (err) free(err); if (retry) { goto again; printk("completing transaction\n"); } goto done; abort_transaction: free(err); err = xenbus_transaction_end(xbt, 1, &retry); goto error; done: snprintf(path, sizeof(path), "%s/backend", nodename); msg = xenbus_read(XBT_NIL, path, &dev->backend); snprintf(path, sizeof(path), "%s/mac", nodename); msg = xenbus_read(XBT_NIL, path, &dev->mac); if ((dev->backend == NULL) || (dev->mac == NULL)) { printk("%s: backend/mac failed\n", __func__); goto error; } printk("backend at %s\n",dev->backend); printk("mac is %s\n",dev->mac); { XenbusState state; char path[strlen(dev->backend) + 1 + 5 + 1]; snprintf(path, sizeof(path), "%s/state", dev->backend); xenbus_watch_path_token(XBT_NIL, path, path, &dev->events); err = NULL; state = xenbus_read_integer(path); while (err == NULL && state < XenbusStateConnected) err = xenbus_wait_for_state_change(path, &state, &dev->events); if (state != XenbusStateConnected) { printk("backend not avalable, state=%d\n", state); xenbus_unwatch_path_token(XBT_NIL, path, path); goto error; } if (ip) { snprintf(path, sizeof(path), "%s/ip", dev->backend); xenbus_read(XBT_NIL, path, ip); } } printk("**************************\n"); unmask_evtchn(dev->evtchn); /* Special conversion specifier 'hh' needed for __ia64__. Without this mini-os panics with 'Unaligned reference'. */ if (rawmac) sscanf(dev->mac,"%hhx:%hhx:%hhx:%hhx:%hhx:%hhx", &rawmac[0], &rawmac[1], &rawmac[2], &rawmac[3], &rawmac[4], &rawmac[5]); return dev; error: free(msg); free(err); free_netfront(dev); return NULL; }
static int xen_pcibk_setup_backend(struct xen_pcibk_device *pdev) { /* Get configuration from xend (if available now) */ int domain, bus, slot, func; int err = 0; int i, num_devs; char dev_str[64]; char state_str[64]; mutex_lock(&pdev->dev_lock); /* It's possible we could get the call to setup twice, so make sure * we're not already connected. */ if (xenbus_read_driver_state(pdev->xdev->nodename) != XenbusStateInitWait) goto out; dev_dbg(&pdev->xdev->dev, "getting be setup\n"); err = xenbus_scanf(XBT_NIL, pdev->xdev->nodename, "num_devs", "%d", &num_devs); if (err != 1) { if (err >= 0) err = -EINVAL; xenbus_dev_fatal(pdev->xdev, err, "Error reading number of devices"); goto out; } for (i = 0; i < num_devs; i++) { int l = snprintf(dev_str, sizeof(dev_str), "dev-%d", i); if (unlikely(l >= (sizeof(dev_str) - 1))) { err = -ENOMEM; xenbus_dev_fatal(pdev->xdev, err, "String overflow while reading " "configuration"); goto out; } err = xenbus_scanf(XBT_NIL, pdev->xdev->nodename, dev_str, "%x:%x:%x.%x", &domain, &bus, &slot, &func); if (err < 0) { xenbus_dev_fatal(pdev->xdev, err, "Error reading device configuration"); goto out; } if (err != 4) { err = -EINVAL; xenbus_dev_fatal(pdev->xdev, err, "Error parsing pci device " "configuration"); goto out; } err = xen_pcibk_export_device(pdev, domain, bus, slot, func, i); if (err) goto out; /* Switch substate of this device. */ l = snprintf(state_str, sizeof(state_str), "state-%d", i); if (unlikely(l >= (sizeof(state_str) - 1))) { err = -ENOMEM; xenbus_dev_fatal(pdev->xdev, err, "String overflow while reading " "configuration"); goto out; } err = xenbus_printf(XBT_NIL, pdev->xdev->nodename, state_str, "%d", XenbusStateInitialised); if (err) { xenbus_dev_fatal(pdev->xdev, err, "Error switching " "substate of dev-%d\n", i); goto out; } } err = xen_pcibk_publish_pci_roots(pdev, xen_pcibk_publish_pci_root); if (err) { xenbus_dev_fatal(pdev->xdev, err, "Error while publish PCI root buses " "for frontend"); goto out; } err = xenbus_switch_state(pdev->xdev, XenbusStateInitialised); if (err) xenbus_dev_fatal(pdev->xdev, err, "Error switching to initialised state!"); out: mutex_unlock(&pdev->dev_lock); if (!err) /* see if pcifront is already configured (if not, we'll wait) */ xen_pcibk_attach(pdev); return err; }
/** * Entry point to this code when a new device is created. Allocate the basic * structures and switch to InitWait. */ static int netback_probe(struct xenbus_device *dev, const struct xenbus_device_id *id) { const char *message; struct xenbus_transaction xbt; int err; int sg; struct backend_info *be = kzalloc(sizeof(struct backend_info), GFP_KERNEL); if (!be) { xenbus_dev_fatal(dev, -ENOMEM, "allocating backend structure"); return -ENOMEM; } be->dev = dev; dev_set_drvdata(&dev->dev, be); sg = 1; do { err = xenbus_transaction_start(&xbt); if (err) { xenbus_dev_fatal(dev, err, "starting transaction"); goto fail; } err = xenbus_printf(xbt, dev->nodename, "feature-sg", "%d", sg); if (err) { message = "writing feature-sg"; goto abort_transaction; } err = xenbus_printf(xbt, dev->nodename, "feature-gso-tcpv4", "%d", sg); if (err) { message = "writing feature-gso-tcpv4"; goto abort_transaction; } err = xenbus_printf(xbt, dev->nodename, "feature-gso-tcpv6", "%d", sg); if (err) { message = "writing feature-gso-tcpv6"; goto abort_transaction; } /* We support partial checksum setup for IPv6 packets */ err = xenbus_printf(xbt, dev->nodename, "feature-ipv6-csum-offload", "%d", 1); if (err) { message = "writing feature-ipv6-csum-offload"; goto abort_transaction; } /* We support rx-copy path. */ err = xenbus_printf(xbt, dev->nodename, "feature-rx-copy", "%d", 1); if (err) { message = "writing feature-rx-copy"; goto abort_transaction; } /* * We don't support rx-flip path (except old guests who don't * grok this feature flag). */ err = xenbus_printf(xbt, dev->nodename, "feature-rx-flip", "%d", 0); if (err) { message = "writing feature-rx-flip"; goto abort_transaction; } err = xenbus_transaction_end(xbt, 0); } while (err == -EAGAIN); if (err) { xenbus_dev_fatal(dev, err, "completing transaction"); goto fail; } /* * Split event channels support, this is optional so it is not * put inside the above loop. */ err = xenbus_printf(XBT_NIL, dev->nodename, "feature-split-event-channels", "%u", separate_tx_rx_irq); if (err) pr_debug("Error writing feature-split-event-channels\n"); /* Multi-queue support: This is an optional feature. */ err = xenbus_printf(XBT_NIL, dev->nodename, "multi-queue-max-queues", "%u", xenvif_max_queues); if (err) pr_debug("Error writing multi-queue-max-queues\n"); err = xenbus_switch_state(dev, XenbusStateInitWait); if (err) goto fail; be->state = XenbusStateInitWait; /* This kicks hotplug scripts, so do it immediately. */ backend_create_xenvif(be); return 0; abort_transaction: xenbus_transaction_end(xbt, 1); xenbus_dev_fatal(dev, err, "%s", message); fail: pr_debug("failed\n"); netback_remove(dev); return err; }
static int xenkbd_connect_backend(struct xenbus_device *dev, struct xenkbd_info *info) { int ret, evtchn; struct xenbus_transaction xbt; ret = gnttab_grant_foreign_access(dev->otherend_id, virt_to_mfn(info->page), 0); if (ret < 0) return ret; info->gref = ret; ret = xenbus_alloc_evtchn(dev, &evtchn); if (ret) goto error_grant; ret = bind_evtchn_to_irqhandler(evtchn, input_handler, 0, dev->devicetype, info); if (ret < 0) { xenbus_dev_fatal(dev, ret, "bind_evtchn_to_irqhandler"); goto error_evtchan; } info->irq = ret; again: ret = xenbus_transaction_start(&xbt); if (ret) { xenbus_dev_fatal(dev, ret, "starting transaction"); goto error_irqh; } ret = xenbus_printf(xbt, dev->nodename, "page-ref", "%lu", virt_to_mfn(info->page)); if (ret) goto error_xenbus; ret = xenbus_printf(xbt, dev->nodename, "page-gref", "%u", info->gref); if (ret) goto error_xenbus; ret = xenbus_printf(xbt, dev->nodename, "event-channel", "%u", evtchn); if (ret) goto error_xenbus; ret = xenbus_transaction_end(xbt, 0); if (ret) { if (ret == -EAGAIN) goto again; xenbus_dev_fatal(dev, ret, "completing transaction"); goto error_irqh; } xenbus_switch_state(dev, XenbusStateInitialised); return 0; error_xenbus: xenbus_transaction_end(xbt, 1); xenbus_dev_fatal(dev, ret, "writing xenstore"); error_irqh: unbind_from_irqhandler(info->irq, info); info->irq = -1; error_evtchan: xenbus_free_evtchn(dev, evtchn); error_grant: gnttab_end_foreign_access_ref(info->gref, 0); info->gref = -1; return ret; }
/* * Write the physical details regarding the block device to the store, and * switch to Connected state. */ static void connect(struct backend_info *be) { struct xenbus_transaction xbt; int err; struct xenbus_device *dev = be->dev; DPRINTK("%s", dev->otherend); /* Supply the information about the device the frontend needs */ again: err = xenbus_transaction_start(&xbt); if (err) { xenbus_dev_fatal(dev, err, "starting transaction"); return; } /* If we can't advertise it is OK. */ xen_blkbk_flush_diskcache(xbt, be, be->blkif->vbd.flush_support); xen_blkbk_discard(xbt, be); xen_blkbk_barrier(xbt, be, be->blkif->vbd.flush_support); err = xenbus_printf(xbt, dev->nodename, "sectors", "%llu", (unsigned long long)vbd_sz(&be->blkif->vbd)); if (err) { xenbus_dev_fatal(dev, err, "writing %s/sectors", dev->nodename); goto abort; } /* FIXME: use a typename instead */ err = xenbus_printf(xbt, dev->nodename, "info", "%u", be->blkif->vbd.type | (be->blkif->vbd.readonly ? VDISK_READONLY : 0)); if (err) { xenbus_dev_fatal(dev, err, "writing %s/info", dev->nodename); goto abort; } err = xenbus_printf(xbt, dev->nodename, "sector-size", "%lu", (unsigned long) bdev_logical_block_size(be->blkif->vbd.bdev)); if (err) { xenbus_dev_fatal(dev, err, "writing %s/sector-size", dev->nodename); goto abort; } err = xenbus_transaction_end(xbt, 0); if (err == -EAGAIN) goto again; if (err) xenbus_dev_fatal(dev, err, "ending transaction"); err = xenbus_switch_state(dev, XenbusStateConnected); if (err) xenbus_dev_fatal(dev, err, "%s: switching to Connected state", dev->nodename); return; abort: xenbus_transaction_end(xbt, 1); }
static int __devinit pcifront_try_connect(struct pcifront_device *pdev) { int err = -EFAULT; int i, num_roots, len; char str[64]; unsigned int domain, bus; spin_lock(&pdev->dev_lock); /* Only connect once */ if (xenbus_read_driver_state(pdev->xdev->nodename) != XenbusStateInitialised) goto out; err = pcifront_connect(pdev); if (err) { xenbus_dev_fatal(pdev->xdev, err, "Error connecting PCI Frontend"); goto out; } err = xenbus_scanf(XBT_NIL, pdev->xdev->otherend, "root_num", "%d", &num_roots); if (err == -ENOENT) { xenbus_dev_error(pdev->xdev, err, "No PCI Roots found, trying 0000:00"); err = pcifront_scan_root(pdev, 0, 0); num_roots = 0; } else if (err != 1) { if (err == 0) err = -EINVAL; xenbus_dev_fatal(pdev->xdev, err, "Error reading number of PCI roots"); goto out; } for (i = 0; i < num_roots; i++) { len = snprintf(str, sizeof(str), "root-%d", i); if (unlikely(len >= (sizeof(str) - 1))) { err = -ENOMEM; goto out; } err = xenbus_scanf(XBT_NIL, pdev->xdev->otherend, str, "%x:%x", &domain, &bus); if (err != 2) { if (err >= 0) err = -EINVAL; xenbus_dev_fatal(pdev->xdev, err, "Error reading PCI root %d", i); goto out; } err = pcifront_scan_root(pdev, domain, bus); if (err) { xenbus_dev_fatal(pdev->xdev, err, "Error scanning PCI root %04x:%02x", domain, bus); goto out; } } err = xenbus_switch_state(pdev->xdev, XenbusStateConnected); if (err) goto out; out: spin_unlock(&pdev->dev_lock); return err; }