]> git.ipfire.org Git - people/pmueller/ipfire-2.x.git/blobdiff - src/patches/suse-2.6.27.25/patches.xen/xen-blkfront-cdrom
Revert "Move xen patchset to new version's subdir."
[people/pmueller/ipfire-2.x.git] / src / patches / suse-2.6.27.25 / patches.xen / xen-blkfront-cdrom
diff --git a/src/patches/suse-2.6.27.25/patches.xen/xen-blkfront-cdrom b/src/patches/suse-2.6.27.25/patches.xen/xen-blkfront-cdrom
new file mode 100644 (file)
index 0000000..1f8120e
--- /dev/null
@@ -0,0 +1,678 @@
+From: plc@novell.com
+Subject: implement forwarding of CD-ROM specific commands
+Patch-mainline: obsolete
+References: fate#300964
+
+--- sle11-2009-06-04.orig/drivers/cdrom/Makefile       2009-06-04 10:17:48.000000000 +0200
++++ sle11-2009-06-04/drivers/cdrom/Makefile    2009-06-04 10:47:04.000000000 +0200
+@@ -9,6 +9,7 @@ obj-$(CONFIG_BLK_DEV_IDECD)    +=          
+ obj-$(CONFIG_BLK_DEV_SR)      +=              cdrom.o
+ obj-$(CONFIG_PARIDE_PCD)      +=              cdrom.o
+ obj-$(CONFIG_CDROM_PKTCDVD)   +=              cdrom.o
++obj-$(CONFIG_XEN_BLKDEV_FRONTEND)     +=              cdrom.o
+ obj-$(CONFIG_VIOCD)           += viocd.o      cdrom.o
+ obj-$(CONFIG_GDROM)           += gdrom.o      cdrom.o
+--- sle11-2009-06-04.orig/drivers/xen/blkfront/Makefile        2009-06-04 10:17:48.000000000 +0200
++++ sle11-2009-06-04/drivers/xen/blkfront/Makefile     2009-06-04 10:47:04.000000000 +0200
+@@ -1,5 +1,5 @@
+ obj-$(CONFIG_XEN_BLKDEV_FRONTEND)     := xenblk.o
+-xenblk-objs := blkfront.o vbd.o
++xenblk-objs := blkfront.o vbd.o vcd.o
+--- sle11-2009-06-04.orig/drivers/xen/blkfront/blkfront.c      2009-06-04 10:46:54.000000000 +0200
++++ sle11-2009-06-04/drivers/xen/blkfront/blkfront.c   2009-06-04 10:47:04.000000000 +0200
+@@ -377,6 +377,8 @@ static void connect(struct blkfront_info
+       add_disk(info->gd);
+       info->is_ready = 1;
++
++      register_vcd(info);
+ }
+ /**
+@@ -407,6 +409,8 @@ static void blkfront_closing(struct xenb
+       xlvbd_sysfs_delif(info);
++      unregister_vcd(info);
++
+       xlvbd_del(info);
+  out:
+--- sle11-2009-06-04.orig/drivers/xen/blkfront/block.h 2009-06-04 10:21:09.000000000 +0200
++++ sle11-2009-06-04/drivers/xen/blkfront/block.h      2009-06-04 10:47:04.000000000 +0200
+@@ -155,4 +155,8 @@ static inline void xlvbd_sysfs_delif(str
+ }
+ #endif
++/* Virtual cdrom block-device */
++extern void register_vcd(struct blkfront_info *info);
++extern void unregister_vcd(struct blkfront_info *info);
++
+ #endif /* __XEN_DRIVERS_BLOCK_H__ */
+--- sle11-2009-06-04.orig/drivers/xen/blkfront/vbd.c   2009-06-04 10:21:09.000000000 +0200
++++ sle11-2009-06-04/drivers/xen/blkfront/vbd.c        2009-06-04 10:47:04.000000000 +0200
+@@ -281,7 +281,8 @@ xlvbd_add(blkif_sector_t capacity, int v
+               goto out;
+       info->mi = mi;
+-      if ((minor & ((1 << mi->type->partn_shift) - 1)) == 0)
++      if (!(vdisk_info & VDISK_CDROM) &&
++          (minor & ((1 << mi->type->partn_shift) - 1)) == 0)
+               nr_minors = 1 << mi->type->partn_shift;
+       gd = alloc_disk(nr_minors);
+@@ -290,7 +291,7 @@ xlvbd_add(blkif_sector_t capacity, int v
+       offset =  mi->index * mi->type->disks_per_major +
+                       (minor >> mi->type->partn_shift);
+-      if (nr_minors > 1) {
++      if (nr_minors > 1 || (vdisk_info & VDISK_CDROM)) {
+               if (offset < 26) {
+                       sprintf(gd->disk_name, "%s%c",
+                                mi->type->diskname, 'a' + offset );
+--- /dev/null  1970-01-01 00:00:00.000000000 +0000
++++ sle11-2009-06-04/drivers/xen/blkfront/vcd.c        2009-06-04 10:47:04.000000000 +0200
+@@ -0,0 +1,476 @@
++/*******************************************************************************
++* vcd.c
++*
++* Implements CDROM cmd packet passing between frontend guest and backend driver.
++*
++* Copyright (c) 2008, Pat Campell  plc@novell.com
++*
++* Permission is hereby granted, free of charge, to any person obtaining a copy
++* of this source file (the "Software"), to deal in the Software without
++* restriction, including without limitation the rights to use, copy, modify,
++* merge, publish, distribute, sublicense, and/or sell copies of the Software,
++* and to permit persons to whom the Software is furnished to do so, subject to
++* the following conditions:
++*
++* The above copyright notice and this permission notice shall be included in
++* all copies or substantial portions of the Software.
++*
++* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
++* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
++* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
++* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
++* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
++* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
++* IN THE SOFTWARE.
++*/
++
++#define REVISION "$Revision: 1.0 $"
++
++#include <linux/module.h>
++#include <linux/blkdev.h>
++#include <linux/list.h>
++#include <linux/cdrom.h>
++#include <xen/interface/io/cdromif.h>
++#include "block.h"
++
++/* List of cdrom_device_info, can have as many as blkfront supports */
++struct vcd_disk {
++      struct list_head vcd_entry;
++      struct cdrom_device_info vcd_cdrom_info;
++      spinlock_t vcd_cdrom_info_lock;
++};
++static LIST_HEAD(vcd_disks);
++static DEFINE_SPINLOCK(vcd_disks_lock);
++
++static struct vcd_disk * xencdrom_get_list_entry(struct gendisk *disk)
++{
++      struct vcd_disk * ret_vcd = NULL;
++      struct vcd_disk * vcd;
++
++      spin_lock(&vcd_disks_lock);
++      list_for_each_entry(vcd, &vcd_disks, vcd_entry) {
++              if (vcd->vcd_cdrom_info.disk == disk) {
++                      spin_lock(&vcd->vcd_cdrom_info_lock);
++                      ret_vcd = vcd;
++                      break;
++              }
++      }
++      spin_unlock(&vcd_disks_lock);
++      return ret_vcd;
++}
++
++static void submit_message(struct blkfront_info *info, void * sp)
++{
++      struct request *req = NULL;
++
++      req = blk_get_request(info->rq, READ, __GFP_WAIT);
++      if (blk_rq_map_kern(info->rq, req, sp, PAGE_SIZE, __GFP_WAIT))
++              goto out;
++
++      req->rq_disk = info->gd;
++#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,18)
++      req->cmd_type = REQ_TYPE_BLOCK_PC;
++      req->cmd_flags |= REQ_NOMERGE;
++#else
++      req->flags |= REQ_BLOCK_PC;
++#endif
++      req->sector = 0;
++      req->nr_sectors = 1;
++      req->timeout = 60*HZ;
++
++      blk_execute_rq(req->q, info->gd, req, 1);
++
++out:
++      blk_put_request(req);
++}
++
++static int submit_cdrom_cmd(struct blkfront_info *info,
++              struct packet_command * cgc)
++{
++      int ret = 0;
++      struct page *page;
++      size_t size;
++      union xen_block_packet *sp;
++      struct xen_cdrom_packet *xcp;
++      struct vcd_generic_command * vgc;
++
++      if (cgc->buffer && cgc->buflen > MAX_PACKET_DATA) {
++              printk(KERN_WARNING "%s() Packet buffer length is to large \n", __func__);
++              return -EIO;
++      }
++
++      page = alloc_page(GFP_NOIO);
++      if (!page) {
++              printk(KERN_CRIT "%s() Unable to allocate page\n", __func__);
++              return -ENOMEM;
++      }
++
++      size = PAGE_SIZE;
++      memset(page_address(page), 0, PAGE_SIZE);
++      sp = page_address(page);
++      xcp = &(sp->xcp);
++      xcp->type = XEN_TYPE_CDROM_PACKET;
++      xcp->payload_offset = PACKET_PAYLOAD_OFFSET;
++
++      vgc = (struct vcd_generic_command *)((char *)sp + xcp->payload_offset);
++      memcpy(vgc->cmd, cgc->cmd, CDROM_PACKET_SIZE);
++      vgc->stat = cgc->stat;
++      vgc->data_direction = cgc->data_direction;
++      vgc->quiet = cgc->quiet;
++      vgc->timeout = cgc->timeout;
++      if (cgc->sense) {
++              vgc->sense_offset = PACKET_SENSE_OFFSET;
++              memcpy((char *)sp + vgc->sense_offset, cgc->sense, sizeof(struct request_sense));
++      }
++      if (cgc->buffer) {
++              vgc->buffer_offset = PACKET_BUFFER_OFFSET;
++              memcpy((char *)sp + vgc->buffer_offset, cgc->buffer, cgc->buflen);
++              vgc->buflen = cgc->buflen;
++      }
++
++      submit_message(info,sp);
++
++      if (xcp->ret)
++              ret = xcp->err;
++
++      if (cgc->sense) {
++              memcpy(cgc->sense, (char *)sp + PACKET_SENSE_OFFSET, sizeof(struct request_sense));
++      }
++      if (cgc->buffer && cgc->buflen) {
++              memcpy(cgc->buffer, (char *)sp + PACKET_BUFFER_OFFSET, cgc->buflen);
++      }
++
++      __free_page(page);
++      return ret;
++}
++
++
++static int xencdrom_open(struct cdrom_device_info *cdi, int purpose)
++{
++      int ret = 0;
++      struct page *page;
++      struct blkfront_info *info;
++      union xen_block_packet *sp;
++      struct xen_cdrom_open *xco;
++
++      info = cdi->disk->private_data;
++
++      if (strlen(info->xbdev->otherend) > MAX_PACKET_DATA) {
++              return -EIO;
++      }
++
++      page = alloc_page(GFP_NOIO);
++      if (!page) {
++              printk(KERN_CRIT "%s() Unable to allocate page\n", __func__);
++              return -ENOMEM;
++      }
++
++      memset(page_address(page), 0, PAGE_SIZE);
++      sp = page_address(page);
++      xco = &(sp->xco);
++      xco->type = XEN_TYPE_CDROM_OPEN;
++      xco->payload_offset = sizeof(struct xen_cdrom_open);
++      strcpy((char *)sp + xco->payload_offset, info->xbdev->otherend);
++
++      submit_message(info,sp);
++
++      if (xco->ret) {
++              ret = xco->err;
++              goto out;
++      }
++
++      if (xco->media_present)
++              set_capacity(cdi->disk, xco->sectors);
++
++out:
++      __free_page(page);
++      return ret;
++}
++
++static void xencdrom_release(struct cdrom_device_info *cdi)
++{
++}
++
++static int xencdrom_media_changed(struct cdrom_device_info *cdi, int disc_nr)
++{
++      int ret;
++      struct page *page;
++      struct blkfront_info *info;
++      union xen_block_packet *sp;
++      struct xen_cdrom_media_changed *xcmc;
++
++      info = cdi->disk->private_data;
++
++      page = alloc_page(GFP_NOIO);
++      if (!page) {
++              printk(KERN_CRIT "%s() Unable to allocate page\n", __func__);
++              return -ENOMEM;
++      }
++
++      memset(page_address(page), 0, PAGE_SIZE);
++      sp = page_address(page);
++      xcmc = &(sp->xcmc);
++      xcmc->type = XEN_TYPE_CDROM_MEDIA_CHANGED;
++      submit_message(info,sp);
++      ret = xcmc->media_changed;
++
++      __free_page(page);
++
++      return ret;
++}
++
++static int xencdrom_tray_move(struct cdrom_device_info *cdi, int position)
++{
++      int ret;
++      struct packet_command cgc;
++      struct blkfront_info *info;
++
++      info = cdi->disk->private_data;
++      init_cdrom_command(&cgc, NULL, 0, CGC_DATA_NONE);
++      cgc.cmd[0] = GPCMD_START_STOP_UNIT;
++      if (position)
++              cgc.cmd[4] = 2;
++      else
++              cgc.cmd[4] = 3;
++      ret = submit_cdrom_cmd(info, &cgc);
++      return ret;
++}
++
++static int xencdrom_lock_door(struct cdrom_device_info *cdi, int lock)
++{
++      int ret = 0;
++      struct blkfront_info *info;
++      struct packet_command cgc;
++
++      info = cdi->disk->private_data;
++      init_cdrom_command(&cgc, NULL, 0, CGC_DATA_NONE);
++      cgc.cmd[0] = GPCMD_PREVENT_ALLOW_MEDIUM_REMOVAL;
++      cgc.cmd[4] = lock;
++      ret = submit_cdrom_cmd(info, &cgc);
++      return ret;
++}
++
++static int xencdrom_packet(struct cdrom_device_info *cdi,
++              struct packet_command *cgc)
++{
++      int ret = -EIO;
++      struct blkfront_info *info;
++
++      info = cdi->disk->private_data;
++      ret = submit_cdrom_cmd(info, cgc);
++      cgc->stat = ret;
++      return ret;
++}
++
++static int xencdrom_audio_ioctl(struct cdrom_device_info *cdi, unsigned int cmd,
++              void *arg)
++{
++      return -EINVAL;
++}
++
++/* Query backend to see if CDROM packets are supported */
++static int xencdrom_supported(struct blkfront_info *info)
++{
++      struct page *page;
++      union xen_block_packet *sp;
++      struct xen_cdrom_support *xcs;
++
++      page = alloc_page(GFP_NOIO);
++      if (!page) {
++              printk(KERN_CRIT "%s() Unable to allocate page\n", __func__);
++              return -ENOMEM;
++      }
++
++      memset(page_address(page), 0, PAGE_SIZE);
++      sp = page_address(page);
++      xcs = &(sp->xcs);
++      xcs->type = XEN_TYPE_CDROM_SUPPORT;
++      submit_message(info,sp);
++      return xcs->supported;
++}
++
++static struct cdrom_device_ops xencdrom_dops = {
++    .open           = xencdrom_open,
++    .release        = xencdrom_release,
++    .media_changed  = xencdrom_media_changed,
++    .tray_move      = xencdrom_tray_move,
++    .lock_door      = xencdrom_lock_door,
++    .generic_packet = xencdrom_packet,
++    .audio_ioctl    = xencdrom_audio_ioctl,
++    .capability     = (CDC_CLOSE_TRAY | CDC_OPEN_TRAY | CDC_LOCK | \
++                       CDC_MEDIA_CHANGED | CDC_GENERIC_PACKET |  CDC_DVD | \
++                       CDC_CD_R),
++    .n_minors       = 1,
++};
++
++static int xencdrom_block_open(struct inode *inode, struct file *file)
++{
++      struct blkfront_info *info = inode->i_bdev->bd_disk->private_data;
++      struct vcd_disk * vcd;
++      int ret = 0;
++
++      if ((vcd = xencdrom_get_list_entry(info->gd))) {
++              ret = cdrom_open(&vcd->vcd_cdrom_info, inode, file);
++              info->users = vcd->vcd_cdrom_info.use_count;
++              spin_unlock(&vcd->vcd_cdrom_info_lock);
++      }
++      return ret;
++}
++
++static int xencdrom_block_release(struct inode *inode, struct file *file)
++{
++      struct blkfront_info *info = inode->i_bdev->bd_disk->private_data;
++      struct vcd_disk * vcd;
++      int ret = 0;
++
++      if ((vcd = xencdrom_get_list_entry(info->gd))) {
++              ret = cdrom_release(&vcd->vcd_cdrom_info, file);
++              spin_unlock(&vcd->vcd_cdrom_info_lock);
++              if (vcd->vcd_cdrom_info.use_count == 0) {
++                      info->users = 1;
++                      blkif_release(inode, file);
++              }
++      }
++      return ret;
++}
++
++static int xencdrom_block_ioctl(struct inode *inode, struct file *file,
++                              unsigned cmd, unsigned long arg)
++{
++      struct blkfront_info *info = inode->i_bdev->bd_disk->private_data;
++      struct vcd_disk * vcd;
++      int ret = 0;
++
++      if (!(vcd = xencdrom_get_list_entry(info->gd)))
++              goto out;
++
++      switch (cmd) {
++              case 2285: /* SG_IO */
++                      ret = -ENOSYS;
++                      break;
++              case CDROMEJECT:
++                      ret = xencdrom_tray_move(&vcd->vcd_cdrom_info, 1);
++                      break;
++              case CDROMCLOSETRAY:
++                      ret = xencdrom_tray_move(&vcd->vcd_cdrom_info, 0);
++                      break;
++              case CDROM_GET_CAPABILITY:
++                      ret = vcd->vcd_cdrom_info.ops->capability & ~vcd->vcd_cdrom_info.mask;
++                      break;
++              case CDROM_SET_OPTIONS:
++                      ret = vcd->vcd_cdrom_info.options;
++                      break;
++              case CDROM_SEND_PACKET:
++                      {
++                              struct packet_command * cgc = (struct packet_command *)arg;
++                              ret = submit_cdrom_cmd(info, cgc);
++                      }
++                      break;
++              default:
++                      /* Not supported, augment supported above if necessary */
++                      printk( "%s():%d Unsupported IOCTL:%x \n", __func__, __LINE__, cmd);
++                      ret = -ENOTTY;
++                      break;
++      }
++      spin_unlock(&vcd->vcd_cdrom_info_lock);
++out:
++      return ret;
++}
++
++/* Called as result of cdrom_open, vcd_cdrom_info_lock already held */
++static int xencdrom_block_media_changed(struct gendisk *disk)
++{
++      struct vcd_disk * vcd;
++      struct vcd_disk * ret_vcd = NULL;
++      int ret = 0;
++
++      spin_lock(&vcd_disks_lock);
++      list_for_each_entry(vcd, &vcd_disks, vcd_entry) {
++              if (vcd->vcd_cdrom_info.disk == disk) {
++                      ret_vcd = vcd;
++                      break;
++              }
++      }
++      spin_unlock(&vcd_disks_lock);
++      if (ret_vcd) {
++              ret = cdrom_media_changed(&ret_vcd->vcd_cdrom_info);
++      }
++      return ret;
++}
++
++static struct block_device_operations xencdrom_bdops =
++{
++      .owner          = THIS_MODULE,
++      .open           = xencdrom_block_open,
++      .release        = xencdrom_block_release,
++      .ioctl          = xencdrom_block_ioctl,
++      .media_changed  = xencdrom_block_media_changed,
++};
++
++void register_vcd(struct blkfront_info *info)
++{
++      struct gendisk * gd = info->gd;
++      struct vcd_disk * vcd;
++
++      /* Make sure this is for a CD device */
++      if (!(gd->flags & GENHD_FL_CD))
++              goto out;
++
++      /* Make sure we have backend support */
++      if (!xencdrom_supported(info)) {
++              goto out;
++      }
++
++      /* Create new vcd_disk and fill in cdrom_info */
++      vcd = (struct vcd_disk *)kzalloc(sizeof(struct vcd_disk), GFP_KERNEL);
++      if (!vcd) {
++              printk(KERN_INFO "%s():  Unable to allocate vcd struct!\n", __func__);
++              goto out;
++      }
++      spin_lock_init(&vcd->vcd_cdrom_info_lock);
++
++      vcd->vcd_cdrom_info.ops = &xencdrom_dops;
++      vcd->vcd_cdrom_info.speed = 4;
++      vcd->vcd_cdrom_info.capacity = 1;
++      vcd->vcd_cdrom_info.options     = 0;
++      strcpy(vcd->vcd_cdrom_info.name, gd->disk_name);
++      vcd->vcd_cdrom_info.mask = ( CDC_CD_RW | CDC_DVD_R | CDC_DVD_RAM |
++                      CDC_SELECT_DISC | CDC_SELECT_SPEED |
++                      CDC_MRW | CDC_MRW_W | CDC_RAM);
++
++      if (register_cdrom(&(vcd->vcd_cdrom_info)) != 0) {
++              printk(KERN_WARNING "%s() Cannot register blkdev as a cdrom %d!\n", __func__,
++                              gd->major);
++              goto err_out;
++      }
++      xencdrom_bdops.owner = gd->fops->owner;
++      gd->fops = &xencdrom_bdops;
++      vcd->vcd_cdrom_info.disk = gd;
++
++      spin_lock(&vcd_disks_lock);
++      list_add(&(vcd->vcd_entry), &vcd_disks);
++      spin_unlock(&vcd_disks_lock);
++out:
++      return;
++err_out:
++      kfree(vcd);
++}
++
++void unregister_vcd(struct blkfront_info *info) {
++      struct gendisk * gd = info->gd;
++      struct vcd_disk * vcd;
++
++      spin_lock(&vcd_disks_lock);
++      list_for_each_entry(vcd, &vcd_disks, vcd_entry) {
++              if (vcd->vcd_cdrom_info.disk == gd) {
++                      spin_lock(&vcd->vcd_cdrom_info_lock);
++                      unregister_cdrom(&vcd->vcd_cdrom_info);
++                      list_del(&vcd->vcd_entry);
++                      spin_unlock(&vcd->vcd_cdrom_info_lock);
++                      kfree(vcd);
++                      break;
++              }
++      }
++      spin_unlock(&vcd_disks_lock);
++}
++
+--- /dev/null  1970-01-01 00:00:00.000000000 +0000
++++ sle11-2009-06-04/include/xen/interface/io/cdromif.h        2009-06-04 10:47:04.000000000 +0200
+@@ -0,0 +1,120 @@
++/******************************************************************************
++ * cdromif.h
++ *
++ * Shared definitions between backend driver and Xen guest Virtual CDROM
++ * block device.
++ *
++ * Copyright (c) 2008, Pat Campell  plc@novell.com
++ *
++ * Permission is hereby granted, free of charge, to any person obtaining a copy
++ * of this source file (the "Software"), to deal in the Software without
++ * restriction, including without limitation the rights to use, copy, modify,
++ * merge, publish, distribute, sublicense, and/or sell copies of the Software,
++ * and to permit persons to whom the Software is furnished to do so, subject to
++ * the following conditions:
++ *
++ * The above copyright notice and this permission notice shall be included in
++ * all copies or substantial portions of the Software.
++ *
++ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
++ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
++ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
++ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
++ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
++ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
++ * IN THE SOFTWARE.
++ */
++
++#ifndef __XEN_PUBLIC_IO_CDROMIF_H__
++#define __XEN_PUBLIC_IO_CDROMIF_H__
++
++/*
++ * Queries backend for CDROM support
++ */
++#define XEN_TYPE_CDROM_SUPPORT         _IO('c', 1)
++
++struct xen_cdrom_support
++{
++      uint32_t type;
++      int8_t ret;                  /* returned, 0 succeded, -1 error */
++      int8_t err;                  /* returned, backend errno */
++      int8_t supported;            /* returned, 1 supported */
++};
++
++/*
++ * Opens backend device, returns drive geometry or
++ * any encountered errors
++ */
++#define XEN_TYPE_CDROM_OPEN            _IO('c', 2)
++
++struct xen_cdrom_open
++{
++      uint32_t type;
++      int8_t ret;
++      int8_t err;
++      int8_t pad;
++      int8_t media_present;        /* returned */
++      uint32_t sectors;            /* returned */
++      uint32_t sector_size;        /* returned */
++      int32_t payload_offset;      /* offset to backend node name payload */
++};
++
++/*
++ * Queries backend for media changed status
++ */
++#define XEN_TYPE_CDROM_MEDIA_CHANGED   _IO('c', 3)
++
++struct xen_cdrom_media_changed
++{
++      uint32_t type;
++      int8_t ret;
++      int8_t err;
++      int8_t media_changed;        /* returned */
++};
++
++/*
++ * Sends vcd generic CDROM packet to backend, followed
++ * immediately by the vcd_generic_command payload
++ */
++#define XEN_TYPE_CDROM_PACKET          _IO('c', 4)
++
++struct xen_cdrom_packet
++{
++      uint32_t type;
++      int8_t ret;
++      int8_t err;
++      int8_t pad[2];
++      int32_t payload_offset;      /* offset to vcd_generic_command payload */
++};
++
++/* CDROM_PACKET_COMMAND, payload for XEN_TYPE_CDROM_PACKET */
++struct vcd_generic_command
++{
++      uint8_t  cmd[CDROM_PACKET_SIZE];
++      uint8_t  pad[4];
++      uint32_t buffer_offset;
++      uint32_t buflen;
++      int32_t  stat;
++      uint32_t sense_offset;
++      uint8_t  data_direction;
++      uint8_t  pad1[3];
++      int32_t  quiet;
++      int32_t  timeout;
++};
++
++union xen_block_packet
++{
++      uint32_t type;
++      struct xen_cdrom_support xcs;
++      struct xen_cdrom_open xco;
++      struct xen_cdrom_media_changed xcmc;
++      struct xen_cdrom_packet xcp;
++};
++
++#define PACKET_PAYLOAD_OFFSET (sizeof(struct xen_cdrom_packet))
++#define PACKET_SENSE_OFFSET (PACKET_PAYLOAD_OFFSET + sizeof(struct vcd_generic_command))
++#define PACKET_BUFFER_OFFSET (PACKET_SENSE_OFFSET + sizeof(struct request_sense))
++#define MAX_PACKET_DATA (PAGE_SIZE - sizeof(struct xen_cdrom_packet) - \
++            sizeof(struct vcd_generic_command) - sizeof(struct request_sense))
++
++#endif