2 Subject: implement forwarding of CD-ROM specific commands
3 Patch-mainline: obsolete
4 References: fate#300964
6 Index: head-2008-10-24/drivers/cdrom/Makefile
7 ===================================================================
8 --- head-2008-10-24.orig/drivers/cdrom/Makefile 2008-10-24 14:05:33.000000000 +0200
9 +++ head-2008-10-24/drivers/cdrom/Makefile 2008-10-01 16:35:07.000000000 +0200
10 @@ -9,6 +9,7 @@ obj-$(CONFIG_BLK_DEV_IDECD) +=
11 obj-$(CONFIG_BLK_DEV_SR) += cdrom.o
12 obj-$(CONFIG_PARIDE_PCD) += cdrom.o
13 obj-$(CONFIG_CDROM_PKTCDVD) += cdrom.o
14 +obj-$(CONFIG_XEN_BLKDEV_FRONTEND) += cdrom.o
16 obj-$(CONFIG_VIOCD) += viocd.o cdrom.o
17 obj-$(CONFIG_GDROM) += gdrom.o cdrom.o
18 Index: head-2008-10-24/drivers/xen/blkfront/Makefile
19 ===================================================================
20 --- head-2008-10-24.orig/drivers/xen/blkfront/Makefile 2008-10-24 14:05:33.000000000 +0200
21 +++ head-2008-10-24/drivers/xen/blkfront/Makefile 2008-10-01 16:35:07.000000000 +0200
24 obj-$(CONFIG_XEN_BLKDEV_FRONTEND) := xenblk.o
26 -xenblk-objs := blkfront.o vbd.o
27 +xenblk-objs := blkfront.o vbd.o vcd.o
29 Index: head-2008-10-24/drivers/xen/blkfront/blkfront.c
30 ===================================================================
31 --- head-2008-10-24.orig/drivers/xen/blkfront/blkfront.c 2008-10-01 16:35:04.000000000 +0200
32 +++ head-2008-10-24/drivers/xen/blkfront/blkfront.c 2008-10-01 16:35:07.000000000 +0200
33 @@ -372,6 +372,8 @@ static void connect(struct blkfront_info
42 @@ -402,6 +404,8 @@ static void blkfront_closing(struct xenb
44 xlvbd_sysfs_delif(info);
46 + unregister_vcd(info);
51 Index: head-2008-10-24/drivers/xen/blkfront/block.h
52 ===================================================================
53 --- head-2008-10-24.orig/drivers/xen/blkfront/block.h 2008-10-24 14:05:33.000000000 +0200
54 +++ head-2008-10-24/drivers/xen/blkfront/block.h 2008-10-01 16:35:07.000000000 +0200
55 @@ -154,4 +154,8 @@ static inline void xlvbd_sysfs_delif(str
59 +/* Virtual cdrom block-device */
60 +extern void register_vcd(struct blkfront_info *info);
61 +extern void unregister_vcd(struct blkfront_info *info);
63 #endif /* __XEN_DRIVERS_BLOCK_H__ */
64 Index: head-2008-10-24/drivers/xen/blkfront/vbd.c
65 ===================================================================
66 --- head-2008-10-24.orig/drivers/xen/blkfront/vbd.c 2008-10-24 14:05:33.000000000 +0200
67 +++ head-2008-10-24/drivers/xen/blkfront/vbd.c 2008-10-24 14:08:33.000000000 +0200
68 @@ -281,7 +281,8 @@ xlvbd_add(blkif_sector_t capacity, int v
72 - if ((minor & ((1 << mi->type->partn_shift) - 1)) == 0)
73 + if (!(vdisk_info & VDISK_CDROM) &&
74 + (minor & ((1 << mi->type->partn_shift) - 1)) == 0)
75 nr_minors = 1 << mi->type->partn_shift;
77 gd = alloc_disk(nr_minors);
78 @@ -290,7 +291,7 @@ xlvbd_add(blkif_sector_t capacity, int v
80 offset = mi->index * mi->type->disks_per_major +
81 (minor >> mi->type->partn_shift);
82 - if (nr_minors > 1) {
83 + if (nr_minors > 1 || (vdisk_info & VDISK_CDROM)) {
85 sprintf(gd->disk_name, "%s%c",
86 mi->type->diskname, 'a' + offset );
87 Index: head-2008-10-24/drivers/xen/blkfront/vcd.c
88 ===================================================================
89 --- /dev/null 1970-01-01 00:00:00.000000000 +0000
90 +++ head-2008-10-24/drivers/xen/blkfront/vcd.c 2008-10-01 16:35:07.000000000 +0200
92 +/*******************************************************************************
95 +* Implements CDROM cmd packet passing between frontend guest and backend driver.
97 +* Copyright (c) 2008, Pat Campell plc@novell.com
99 +* Permission is hereby granted, free of charge, to any person obtaining a copy
100 +* of this source file (the "Software"), to deal in the Software without
101 +* restriction, including without limitation the rights to use, copy, modify,
102 +* merge, publish, distribute, sublicense, and/or sell copies of the Software,
103 +* and to permit persons to whom the Software is furnished to do so, subject to
104 +* the following conditions:
106 +* The above copyright notice and this permission notice shall be included in
107 +* all copies or substantial portions of the Software.
109 +* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
110 +* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
111 +* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
112 +* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
113 +* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
114 +* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
118 +#define REVISION "$Revision: 1.0 $"
120 +#include <linux/module.h>
121 +#include <linux/blkdev.h>
122 +#include <linux/list.h>
123 +#include <linux/cdrom.h>
124 +#include <xen/interface/io/cdromif.h>
127 +/* List of cdrom_device_info, can have as many as blkfront supports */
129 + struct list_head vcd_entry;
130 + struct cdrom_device_info vcd_cdrom_info;
131 + spinlock_t vcd_cdrom_info_lock;
133 +static LIST_HEAD(vcd_disks);
134 +static DEFINE_SPINLOCK(vcd_disks_lock);
136 +static struct vcd_disk * xencdrom_get_list_entry(struct gendisk *disk)
138 + struct vcd_disk * ret_vcd = NULL;
139 + struct vcd_disk * vcd;
141 + spin_lock(&vcd_disks_lock);
142 + list_for_each_entry(vcd, &vcd_disks, vcd_entry) {
143 + if (vcd->vcd_cdrom_info.disk == disk) {
144 + spin_lock(&vcd->vcd_cdrom_info_lock);
149 + spin_unlock(&vcd_disks_lock);
153 +static void submit_message(struct blkfront_info *info, void * sp)
155 + struct request *req = NULL;
157 + req = blk_get_request(info->rq, READ, __GFP_WAIT);
158 + if (blk_rq_map_kern(info->rq, req, sp, PAGE_SIZE, __GFP_WAIT))
161 + req->rq_disk = info->gd;
162 +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,18)
163 + req->cmd_type = REQ_TYPE_BLOCK_PC;
164 + req->cmd_flags |= REQ_NOMERGE;
166 + req->flags |= REQ_BLOCK_PC;
169 + req->nr_sectors = 1;
170 + req->timeout = 60*HZ;
172 + blk_execute_rq(req->q, info->gd, req, 1);
175 + blk_put_request(req);
178 +static int submit_cdrom_cmd(struct blkfront_info *info,
179 + struct packet_command * cgc)
184 + union xen_block_packet *sp;
185 + struct xen_cdrom_packet *xcp;
186 + struct vcd_generic_command * vgc;
188 + if (cgc->buffer && cgc->buflen > MAX_PACKET_DATA) {
189 + printk(KERN_WARNING "%s() Packet buffer length is to large \n", __func__);
193 + page = alloc_page(GFP_NOIO);
195 + printk(KERN_CRIT "%s() Unable to allocate page\n", __func__);
200 + memset(page_address(page), 0, PAGE_SIZE);
201 + sp = page_address(page);
203 + xcp->type = XEN_TYPE_CDROM_PACKET;
204 + xcp->payload_offset = PACKET_PAYLOAD_OFFSET;
206 + vgc = (struct vcd_generic_command *)((char *)sp + xcp->payload_offset);
207 + memcpy(vgc->cmd, cgc->cmd, CDROM_PACKET_SIZE);
208 + vgc->stat = cgc->stat;
209 + vgc->data_direction = cgc->data_direction;
210 + vgc->quiet = cgc->quiet;
211 + vgc->timeout = cgc->timeout;
213 + vgc->sense_offset = PACKET_SENSE_OFFSET;
214 + memcpy((char *)sp + vgc->sense_offset, cgc->sense, sizeof(struct request_sense));
217 + vgc->buffer_offset = PACKET_BUFFER_OFFSET;
218 + memcpy((char *)sp + vgc->buffer_offset, cgc->buffer, cgc->buflen);
219 + vgc->buflen = cgc->buflen;
222 + submit_message(info,sp);
228 + memcpy(cgc->sense, (char *)sp + PACKET_SENSE_OFFSET, sizeof(struct request_sense));
230 + if (cgc->buffer && cgc->buflen) {
231 + memcpy(cgc->buffer, (char *)sp + PACKET_BUFFER_OFFSET, cgc->buflen);
239 +static int xencdrom_open(struct cdrom_device_info *cdi, int purpose)
243 + struct blkfront_info *info;
244 + union xen_block_packet *sp;
245 + struct xen_cdrom_open *xco;
247 + info = cdi->disk->private_data;
249 + if (strlen(info->xbdev->otherend) > MAX_PACKET_DATA) {
253 + page = alloc_page(GFP_NOIO);
255 + printk(KERN_CRIT "%s() Unable to allocate page\n", __func__);
259 + memset(page_address(page), 0, PAGE_SIZE);
260 + sp = page_address(page);
262 + xco->type = XEN_TYPE_CDROM_OPEN;
263 + xco->payload_offset = sizeof(struct xen_cdrom_open);
264 + strcpy((char *)sp + xco->payload_offset, info->xbdev->otherend);
266 + submit_message(info,sp);
273 + if (xco->media_present)
274 + set_capacity(cdi->disk, xco->sectors);
281 +static void xencdrom_release(struct cdrom_device_info *cdi)
285 +static int xencdrom_media_changed(struct cdrom_device_info *cdi, int disc_nr)
289 + struct blkfront_info *info;
290 + union xen_block_packet *sp;
291 + struct xen_cdrom_media_changed *xcmc;
293 + info = cdi->disk->private_data;
295 + page = alloc_page(GFP_NOIO);
297 + printk(KERN_CRIT "%s() Unable to allocate page\n", __func__);
301 + memset(page_address(page), 0, PAGE_SIZE);
302 + sp = page_address(page);
303 + xcmc = &(sp->xcmc);
304 + xcmc->type = XEN_TYPE_CDROM_MEDIA_CHANGED;
305 + submit_message(info,sp);
306 + ret = xcmc->media_changed;
313 +static int xencdrom_tray_move(struct cdrom_device_info *cdi, int position)
316 + struct packet_command cgc;
317 + struct blkfront_info *info;
319 + info = cdi->disk->private_data;
320 + init_cdrom_command(&cgc, NULL, 0, CGC_DATA_NONE);
321 + cgc.cmd[0] = GPCMD_START_STOP_UNIT;
326 + ret = submit_cdrom_cmd(info, &cgc);
330 +static int xencdrom_lock_door(struct cdrom_device_info *cdi, int lock)
333 + struct blkfront_info *info;
334 + struct packet_command cgc;
336 + info = cdi->disk->private_data;
337 + init_cdrom_command(&cgc, NULL, 0, CGC_DATA_NONE);
338 + cgc.cmd[0] = GPCMD_PREVENT_ALLOW_MEDIUM_REMOVAL;
340 + ret = submit_cdrom_cmd(info, &cgc);
344 +static int xencdrom_packet(struct cdrom_device_info *cdi,
345 + struct packet_command *cgc)
348 + struct blkfront_info *info;
350 + info = cdi->disk->private_data;
351 + ret = submit_cdrom_cmd(info, cgc);
356 +static int xencdrom_audio_ioctl(struct cdrom_device_info *cdi, unsigned int cmd,
362 +/* Query backend to see if CDROM packets are supported */
363 +static int xencdrom_supported(struct blkfront_info *info)
366 + union xen_block_packet *sp;
367 + struct xen_cdrom_support *xcs;
369 + page = alloc_page(GFP_NOIO);
371 + printk(KERN_CRIT "%s() Unable to allocate page\n", __func__);
375 + memset(page_address(page), 0, PAGE_SIZE);
376 + sp = page_address(page);
378 + xcs->type = XEN_TYPE_CDROM_SUPPORT;
379 + submit_message(info,sp);
380 + return xcs->supported;
383 +static struct cdrom_device_ops xencdrom_dops = {
384 + .open = xencdrom_open,
385 + .release = xencdrom_release,
386 + .media_changed = xencdrom_media_changed,
387 + .tray_move = xencdrom_tray_move,
388 + .lock_door = xencdrom_lock_door,
389 + .generic_packet = xencdrom_packet,
390 + .audio_ioctl = xencdrom_audio_ioctl,
391 + .capability = (CDC_CLOSE_TRAY | CDC_OPEN_TRAY | CDC_LOCK | \
392 + CDC_MEDIA_CHANGED | CDC_GENERIC_PACKET | CDC_DVD | \
397 +static int xencdrom_block_open(struct inode *inode, struct file *file)
399 + struct blkfront_info *info = inode->i_bdev->bd_disk->private_data;
400 + struct vcd_disk * vcd;
403 + if ((vcd = xencdrom_get_list_entry(info->gd))) {
404 + ret = cdrom_open(&vcd->vcd_cdrom_info, inode, file);
405 + info->users = vcd->vcd_cdrom_info.use_count;
406 + spin_unlock(&vcd->vcd_cdrom_info_lock);
411 +static int xencdrom_block_release(struct inode *inode, struct file *file)
413 + struct blkfront_info *info = inode->i_bdev->bd_disk->private_data;
414 + struct vcd_disk * vcd;
417 + if ((vcd = xencdrom_get_list_entry(info->gd))) {
418 + ret = cdrom_release(&vcd->vcd_cdrom_info, file);
419 + spin_unlock(&vcd->vcd_cdrom_info_lock);
420 + if (vcd->vcd_cdrom_info.use_count == 0) {
422 + blkif_release(inode, file);
428 +static int xencdrom_block_ioctl(struct inode *inode, struct file *file,
429 + unsigned cmd, unsigned long arg)
431 + struct blkfront_info *info = inode->i_bdev->bd_disk->private_data;
432 + struct vcd_disk * vcd;
435 + if (!(vcd = xencdrom_get_list_entry(info->gd)))
439 + case 2285: /* SG_IO */
443 + ret = xencdrom_tray_move(&vcd->vcd_cdrom_info, 1);
445 + case CDROMCLOSETRAY:
446 + ret = xencdrom_tray_move(&vcd->vcd_cdrom_info, 0);
448 + case CDROM_GET_CAPABILITY:
449 + ret = vcd->vcd_cdrom_info.ops->capability & ~vcd->vcd_cdrom_info.mask;
451 + case CDROM_SET_OPTIONS:
452 + ret = vcd->vcd_cdrom_info.options;
454 + case CDROM_SEND_PACKET:
456 + struct packet_command * cgc = (struct packet_command *)arg;
457 + ret = submit_cdrom_cmd(info, cgc);
461 + /* Not supported, augment supported above if necessary */
462 + printk( "%s():%d Unsupported IOCTL:%x \n", __func__, __LINE__, cmd);
466 + spin_unlock(&vcd->vcd_cdrom_info_lock);
471 +/* Called as result of cdrom_open, vcd_cdrom_info_lock already held */
472 +static int xencdrom_block_media_changed(struct gendisk *disk)
474 + struct vcd_disk * vcd;
475 + struct vcd_disk * ret_vcd = NULL;
478 + spin_lock(&vcd_disks_lock);
479 + list_for_each_entry(vcd, &vcd_disks, vcd_entry) {
480 + if (vcd->vcd_cdrom_info.disk == disk) {
485 + spin_unlock(&vcd_disks_lock);
487 + ret = cdrom_media_changed(&ret_vcd->vcd_cdrom_info);
492 +static struct block_device_operations xencdrom_bdops =
494 + .owner = THIS_MODULE,
495 + .open = xencdrom_block_open,
496 + .release = xencdrom_block_release,
497 + .ioctl = xencdrom_block_ioctl,
498 + .media_changed = xencdrom_block_media_changed,
501 +void register_vcd(struct blkfront_info *info)
503 + struct gendisk * gd = info->gd;
504 + struct vcd_disk * vcd;
506 + /* Make sure this is for a CD device */
507 + if (!(gd->flags & GENHD_FL_CD))
510 + /* Make sure we have backend support */
511 + if (!xencdrom_supported(info)) {
515 + /* Create new vcd_disk and fill in cdrom_info */
516 + vcd = (struct vcd_disk *)kzalloc(sizeof(struct vcd_disk), GFP_KERNEL);
518 + printk(KERN_INFO "%s(): Unable to allocate vcd struct!\n", __func__);
521 + spin_lock_init(&vcd->vcd_cdrom_info_lock);
523 + vcd->vcd_cdrom_info.ops = &xencdrom_dops;
524 + vcd->vcd_cdrom_info.speed = 4;
525 + vcd->vcd_cdrom_info.capacity = 1;
526 + vcd->vcd_cdrom_info.options = 0;
527 + strcpy(vcd->vcd_cdrom_info.name, gd->disk_name);
528 + vcd->vcd_cdrom_info.mask = ( CDC_CD_RW | CDC_DVD_R | CDC_DVD_RAM |
529 + CDC_SELECT_DISC | CDC_SELECT_SPEED |
530 + CDC_MRW | CDC_MRW_W | CDC_RAM);
532 + if (register_cdrom(&(vcd->vcd_cdrom_info)) != 0) {
533 + printk(KERN_WARNING "%s() Cannot register blkdev as a cdrom %d!\n", __func__,
537 + xencdrom_bdops.owner = gd->fops->owner;
538 + gd->fops = &xencdrom_bdops;
539 + vcd->vcd_cdrom_info.disk = gd;
541 + spin_lock(&vcd_disks_lock);
542 + list_add(&(vcd->vcd_entry), &vcd_disks);
543 + spin_unlock(&vcd_disks_lock);
550 +void unregister_vcd(struct blkfront_info *info) {
551 + struct gendisk * gd = info->gd;
552 + struct vcd_disk * vcd;
554 + spin_lock(&vcd_disks_lock);
555 + list_for_each_entry(vcd, &vcd_disks, vcd_entry) {
556 + if (vcd->vcd_cdrom_info.disk == gd) {
557 + spin_lock(&vcd->vcd_cdrom_info_lock);
558 + unregister_cdrom(&vcd->vcd_cdrom_info);
559 + list_del(&vcd->vcd_entry);
560 + spin_unlock(&vcd->vcd_cdrom_info_lock);
565 + spin_unlock(&vcd_disks_lock);
568 Index: head-2008-10-24/include/xen/interface/io/cdromif.h
569 ===================================================================
570 --- /dev/null 1970-01-01 00:00:00.000000000 +0000
571 +++ head-2008-10-24/include/xen/interface/io/cdromif.h 2008-10-01 16:35:07.000000000 +0200
573 +/******************************************************************************
576 + * Shared definitions between backend driver and Xen guest Virtual CDROM
579 + * Copyright (c) 2008, Pat Campell plc@novell.com
581 + * Permission is hereby granted, free of charge, to any person obtaining a copy
582 + * of this source file (the "Software"), to deal in the Software without
583 + * restriction, including without limitation the rights to use, copy, modify,
584 + * merge, publish, distribute, sublicense, and/or sell copies of the Software,
585 + * and to permit persons to whom the Software is furnished to do so, subject to
586 + * the following conditions:
588 + * The above copyright notice and this permission notice shall be included in
589 + * all copies or substantial portions of the Software.
591 + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
592 + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
593 + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
594 + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
595 + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
596 + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
600 +#ifndef __XEN_PUBLIC_IO_CDROMIF_H__
601 +#define __XEN_PUBLIC_IO_CDROMIF_H__
604 + * Queries backend for CDROM support
606 +#define XEN_TYPE_CDROM_SUPPORT _IO('c', 1)
608 +struct xen_cdrom_support
611 + int8_t ret; /* returned, 0 succeded, -1 error */
612 + int8_t err; /* returned, backend errno */
613 + int8_t supported; /* returned, 1 supported */
617 + * Opens backend device, returns drive geometry or
618 + * any encountered errors
620 +#define XEN_TYPE_CDROM_OPEN _IO('c', 2)
622 +struct xen_cdrom_open
628 + int8_t media_present; /* returned */
629 + uint32_t sectors; /* returned */
630 + uint32_t sector_size; /* returned */
631 + int32_t payload_offset; /* offset to backend node name payload */
635 + * Queries backend for media changed status
637 +#define XEN_TYPE_CDROM_MEDIA_CHANGED _IO('c', 3)
639 +struct xen_cdrom_media_changed
644 + int8_t media_changed; /* returned */
648 + * Sends vcd generic CDROM packet to backend, followed
649 + * immediately by the vcd_generic_command payload
651 +#define XEN_TYPE_CDROM_PACKET _IO('c', 4)
653 +struct xen_cdrom_packet
659 + int32_t payload_offset; /* offset to vcd_generic_command payload */
662 +/* CDROM_PACKET_COMMAND, payload for XEN_TYPE_CDROM_PACKET */
663 +struct vcd_generic_command
665 + uint8_t cmd[CDROM_PACKET_SIZE];
667 + uint32_t buffer_offset;
670 + uint32_t sense_offset;
671 + uint8_t data_direction;
677 +union xen_block_packet
680 + struct xen_cdrom_support xcs;
681 + struct xen_cdrom_open xco;
682 + struct xen_cdrom_media_changed xcmc;
683 + struct xen_cdrom_packet xcp;
686 +#define PACKET_PAYLOAD_OFFSET (sizeof(struct xen_cdrom_packet))
687 +#define PACKET_SENSE_OFFSET (PACKET_PAYLOAD_OFFSET + sizeof(struct vcd_generic_command))
688 +#define PACKET_BUFFER_OFFSET (PACKET_SENSE_OFFSET + sizeof(struct request_sense))
689 +#define MAX_PACKET_DATA (PAGE_SIZE - sizeof(struct xen_cdrom_packet) - \
690 + sizeof(struct vcd_generic_command) - sizeof(struct request_sense))