]>
Commit | Line | Data |
---|---|---|
cc90b958 BS |
1 | From: plc@novell.com |
2 | Subject: implement forwarding of CD-ROM specific commands | |
3 | Patch-mainline: obsolete | |
4 | References: fate#300964 | |
5 | ||
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 | |
15 | ||
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 | |
22 | @@ -1,5 +1,5 @@ | |
23 | ||
24 | obj-$(CONFIG_XEN_BLKDEV_FRONTEND) := xenblk.o | |
25 | ||
26 | -xenblk-objs := blkfront.o vbd.o | |
27 | +xenblk-objs := blkfront.o vbd.o vcd.o | |
28 | ||
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 | |
34 | add_disk(info->gd); | |
35 | ||
36 | info->is_ready = 1; | |
37 | + | |
38 | + register_vcd(info); | |
39 | } | |
40 | ||
41 | /** | |
42 | @@ -402,6 +404,8 @@ static void blkfront_closing(struct xenb | |
43 | ||
44 | xlvbd_sysfs_delif(info); | |
45 | ||
46 | + unregister_vcd(info); | |
47 | + | |
48 | xlvbd_del(info); | |
49 | ||
50 | out: | |
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 | |
56 | } | |
57 | #endif | |
58 | ||
59 | +/* Virtual cdrom block-device */ | |
60 | +extern void register_vcd(struct blkfront_info *info); | |
61 | +extern void unregister_vcd(struct blkfront_info *info); | |
62 | + | |
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 | |
69 | goto out; | |
70 | info->mi = mi; | |
71 | ||
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; | |
76 | ||
77 | gd = alloc_disk(nr_minors); | |
78 | @@ -290,7 +291,7 @@ xlvbd_add(blkif_sector_t capacity, int v | |
79 | ||
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)) { | |
84 | if (offset < 26) { | |
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 | |
91 | @@ -0,0 +1,476 @@ | |
92 | +/******************************************************************************* | |
93 | +* vcd.c | |
94 | +* | |
95 | +* Implements CDROM cmd packet passing between frontend guest and backend driver. | |
96 | +* | |
97 | +* Copyright (c) 2008, Pat Campell plc@novell.com | |
98 | +* | |
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: | |
105 | +* | |
106 | +* The above copyright notice and this permission notice shall be included in | |
107 | +* all copies or substantial portions of the Software. | |
108 | +* | |
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 | |
115 | +* IN THE SOFTWARE. | |
116 | +*/ | |
117 | + | |
118 | +#define REVISION "$Revision: 1.0 $" | |
119 | + | |
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> | |
125 | +#include "block.h" | |
126 | + | |
127 | +/* List of cdrom_device_info, can have as many as blkfront supports */ | |
128 | +struct vcd_disk { | |
129 | + struct list_head vcd_entry; | |
130 | + struct cdrom_device_info vcd_cdrom_info; | |
131 | + spinlock_t vcd_cdrom_info_lock; | |
132 | +}; | |
133 | +static LIST_HEAD(vcd_disks); | |
134 | +static DEFINE_SPINLOCK(vcd_disks_lock); | |
135 | + | |
136 | +static struct vcd_disk * xencdrom_get_list_entry(struct gendisk *disk) | |
137 | +{ | |
138 | + struct vcd_disk * ret_vcd = NULL; | |
139 | + struct vcd_disk * vcd; | |
140 | + | |
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); | |
145 | + ret_vcd = vcd; | |
146 | + break; | |
147 | + } | |
148 | + } | |
149 | + spin_unlock(&vcd_disks_lock); | |
150 | + return ret_vcd; | |
151 | +} | |
152 | + | |
153 | +static void submit_message(struct blkfront_info *info, void * sp) | |
154 | +{ | |
155 | + struct request *req = NULL; | |
156 | + | |
157 | + req = blk_get_request(info->rq, READ, __GFP_WAIT); | |
158 | + if (blk_rq_map_kern(info->rq, req, sp, PAGE_SIZE, __GFP_WAIT)) | |
159 | + goto out; | |
160 | + | |
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; | |
165 | +#else | |
166 | + req->flags |= REQ_BLOCK_PC; | |
167 | +#endif | |
168 | + req->sector = 0; | |
169 | + req->nr_sectors = 1; | |
170 | + req->timeout = 60*HZ; | |
171 | + | |
172 | + blk_execute_rq(req->q, info->gd, req, 1); | |
173 | + | |
174 | +out: | |
175 | + blk_put_request(req); | |
176 | +} | |
177 | + | |
178 | +static int submit_cdrom_cmd(struct blkfront_info *info, | |
179 | + struct packet_command * cgc) | |
180 | +{ | |
181 | + int ret = 0; | |
182 | + struct page *page; | |
183 | + size_t size; | |
184 | + union xen_block_packet *sp; | |
185 | + struct xen_cdrom_packet *xcp; | |
186 | + struct vcd_generic_command * vgc; | |
187 | + | |
188 | + if (cgc->buffer && cgc->buflen > MAX_PACKET_DATA) { | |
189 | + printk(KERN_WARNING "%s() Packet buffer length is to large \n", __func__); | |
190 | + return -EIO; | |
191 | + } | |
192 | + | |
193 | + page = alloc_page(GFP_NOIO); | |
194 | + if (!page) { | |
195 | + printk(KERN_CRIT "%s() Unable to allocate page\n", __func__); | |
196 | + return -ENOMEM; | |
197 | + } | |
198 | + | |
199 | + size = PAGE_SIZE; | |
200 | + memset(page_address(page), 0, PAGE_SIZE); | |
201 | + sp = page_address(page); | |
202 | + xcp = &(sp->xcp); | |
203 | + xcp->type = XEN_TYPE_CDROM_PACKET; | |
204 | + xcp->payload_offset = PACKET_PAYLOAD_OFFSET; | |
205 | + | |
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; | |
212 | + if (cgc->sense) { | |
213 | + vgc->sense_offset = PACKET_SENSE_OFFSET; | |
214 | + memcpy((char *)sp + vgc->sense_offset, cgc->sense, sizeof(struct request_sense)); | |
215 | + } | |
216 | + if (cgc->buffer) { | |
217 | + vgc->buffer_offset = PACKET_BUFFER_OFFSET; | |
218 | + memcpy((char *)sp + vgc->buffer_offset, cgc->buffer, cgc->buflen); | |
219 | + vgc->buflen = cgc->buflen; | |
220 | + } | |
221 | + | |
222 | + submit_message(info,sp); | |
223 | + | |
224 | + if (xcp->ret) | |
225 | + ret = xcp->err; | |
226 | + | |
227 | + if (cgc->sense) { | |
228 | + memcpy(cgc->sense, (char *)sp + PACKET_SENSE_OFFSET, sizeof(struct request_sense)); | |
229 | + } | |
230 | + if (cgc->buffer && cgc->buflen) { | |
231 | + memcpy(cgc->buffer, (char *)sp + PACKET_BUFFER_OFFSET, cgc->buflen); | |
232 | + } | |
233 | + | |
234 | + __free_page(page); | |
235 | + return ret; | |
236 | +} | |
237 | + | |
238 | + | |
239 | +static int xencdrom_open(struct cdrom_device_info *cdi, int purpose) | |
240 | +{ | |
241 | + int ret = 0; | |
242 | + struct page *page; | |
243 | + struct blkfront_info *info; | |
244 | + union xen_block_packet *sp; | |
245 | + struct xen_cdrom_open *xco; | |
246 | + | |
247 | + info = cdi->disk->private_data; | |
248 | + | |
249 | + if (strlen(info->xbdev->otherend) > MAX_PACKET_DATA) { | |
250 | + return -EIO; | |
251 | + } | |
252 | + | |
253 | + page = alloc_page(GFP_NOIO); | |
254 | + if (!page) { | |
255 | + printk(KERN_CRIT "%s() Unable to allocate page\n", __func__); | |
256 | + return -ENOMEM; | |
257 | + } | |
258 | + | |
259 | + memset(page_address(page), 0, PAGE_SIZE); | |
260 | + sp = page_address(page); | |
261 | + xco = &(sp->xco); | |
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); | |
265 | + | |
266 | + submit_message(info,sp); | |
267 | + | |
268 | + if (xco->ret) { | |
269 | + ret = xco->err; | |
270 | + goto out; | |
271 | + } | |
272 | + | |
273 | + if (xco->media_present) | |
274 | + set_capacity(cdi->disk, xco->sectors); | |
275 | + | |
276 | +out: | |
277 | + __free_page(page); | |
278 | + return ret; | |
279 | +} | |
280 | + | |
281 | +static void xencdrom_release(struct cdrom_device_info *cdi) | |
282 | +{ | |
283 | +} | |
284 | + | |
285 | +static int xencdrom_media_changed(struct cdrom_device_info *cdi, int disc_nr) | |
286 | +{ | |
287 | + int ret; | |
288 | + struct page *page; | |
289 | + struct blkfront_info *info; | |
290 | + union xen_block_packet *sp; | |
291 | + struct xen_cdrom_media_changed *xcmc; | |
292 | + | |
293 | + info = cdi->disk->private_data; | |
294 | + | |
295 | + page = alloc_page(GFP_NOIO); | |
296 | + if (!page) { | |
297 | + printk(KERN_CRIT "%s() Unable to allocate page\n", __func__); | |
298 | + return -ENOMEM; | |
299 | + } | |
300 | + | |
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; | |
307 | + | |
308 | + __free_page(page); | |
309 | + | |
310 | + return ret; | |
311 | +} | |
312 | + | |
313 | +static int xencdrom_tray_move(struct cdrom_device_info *cdi, int position) | |
314 | +{ | |
315 | + int ret; | |
316 | + struct packet_command cgc; | |
317 | + struct blkfront_info *info; | |
318 | + | |
319 | + info = cdi->disk->private_data; | |
320 | + init_cdrom_command(&cgc, NULL, 0, CGC_DATA_NONE); | |
321 | + cgc.cmd[0] = GPCMD_START_STOP_UNIT; | |
322 | + if (position) | |
323 | + cgc.cmd[4] = 2; | |
324 | + else | |
325 | + cgc.cmd[4] = 3; | |
326 | + ret = submit_cdrom_cmd(info, &cgc); | |
327 | + return ret; | |
328 | +} | |
329 | + | |
330 | +static int xencdrom_lock_door(struct cdrom_device_info *cdi, int lock) | |
331 | +{ | |
332 | + int ret = 0; | |
333 | + struct blkfront_info *info; | |
334 | + struct packet_command cgc; | |
335 | + | |
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; | |
339 | + cgc.cmd[4] = lock; | |
340 | + ret = submit_cdrom_cmd(info, &cgc); | |
341 | + return ret; | |
342 | +} | |
343 | + | |
344 | +static int xencdrom_packet(struct cdrom_device_info *cdi, | |
345 | + struct packet_command *cgc) | |
346 | +{ | |
347 | + int ret = -EIO; | |
348 | + struct blkfront_info *info; | |
349 | + | |
350 | + info = cdi->disk->private_data; | |
351 | + ret = submit_cdrom_cmd(info, cgc); | |
352 | + cgc->stat = ret; | |
353 | + return ret; | |
354 | +} | |
355 | + | |
356 | +static int xencdrom_audio_ioctl(struct cdrom_device_info *cdi, unsigned int cmd, | |
357 | + void *arg) | |
358 | +{ | |
359 | + return -EINVAL; | |
360 | +} | |
361 | + | |
362 | +/* Query backend to see if CDROM packets are supported */ | |
363 | +static int xencdrom_supported(struct blkfront_info *info) | |
364 | +{ | |
365 | + struct page *page; | |
366 | + union xen_block_packet *sp; | |
367 | + struct xen_cdrom_support *xcs; | |
368 | + | |
369 | + page = alloc_page(GFP_NOIO); | |
370 | + if (!page) { | |
371 | + printk(KERN_CRIT "%s() Unable to allocate page\n", __func__); | |
372 | + return -ENOMEM; | |
373 | + } | |
374 | + | |
375 | + memset(page_address(page), 0, PAGE_SIZE); | |
376 | + sp = page_address(page); | |
377 | + xcs = &(sp->xcs); | |
378 | + xcs->type = XEN_TYPE_CDROM_SUPPORT; | |
379 | + submit_message(info,sp); | |
380 | + return xcs->supported; | |
381 | +} | |
382 | + | |
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 | \ | |
393 | + CDC_CD_R), | |
394 | + .n_minors = 1, | |
395 | +}; | |
396 | + | |
397 | +static int xencdrom_block_open(struct inode *inode, struct file *file) | |
398 | +{ | |
399 | + struct blkfront_info *info = inode->i_bdev->bd_disk->private_data; | |
400 | + struct vcd_disk * vcd; | |
401 | + int ret = 0; | |
402 | + | |
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); | |
407 | + } | |
408 | + return ret; | |
409 | +} | |
410 | + | |
411 | +static int xencdrom_block_release(struct inode *inode, struct file *file) | |
412 | +{ | |
413 | + struct blkfront_info *info = inode->i_bdev->bd_disk->private_data; | |
414 | + struct vcd_disk * vcd; | |
415 | + int ret = 0; | |
416 | + | |
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) { | |
421 | + info->users = 1; | |
422 | + blkif_release(inode, file); | |
423 | + } | |
424 | + } | |
425 | + return ret; | |
426 | +} | |
427 | + | |
428 | +static int xencdrom_block_ioctl(struct inode *inode, struct file *file, | |
429 | + unsigned cmd, unsigned long arg) | |
430 | +{ | |
431 | + struct blkfront_info *info = inode->i_bdev->bd_disk->private_data; | |
432 | + struct vcd_disk * vcd; | |
433 | + int ret = 0; | |
434 | + | |
435 | + if (!(vcd = xencdrom_get_list_entry(info->gd))) | |
436 | + goto out; | |
437 | + | |
438 | + switch (cmd) { | |
439 | + case 2285: /* SG_IO */ | |
440 | + ret = -ENOSYS; | |
441 | + break; | |
442 | + case CDROMEJECT: | |
443 | + ret = xencdrom_tray_move(&vcd->vcd_cdrom_info, 1); | |
444 | + break; | |
445 | + case CDROMCLOSETRAY: | |
446 | + ret = xencdrom_tray_move(&vcd->vcd_cdrom_info, 0); | |
447 | + break; | |
448 | + case CDROM_GET_CAPABILITY: | |
449 | + ret = vcd->vcd_cdrom_info.ops->capability & ~vcd->vcd_cdrom_info.mask; | |
450 | + break; | |
451 | + case CDROM_SET_OPTIONS: | |
452 | + ret = vcd->vcd_cdrom_info.options; | |
453 | + break; | |
454 | + case CDROM_SEND_PACKET: | |
455 | + { | |
456 | + struct packet_command * cgc = (struct packet_command *)arg; | |
457 | + ret = submit_cdrom_cmd(info, cgc); | |
458 | + } | |
459 | + break; | |
460 | + default: | |
461 | + /* Not supported, augment supported above if necessary */ | |
462 | + printk( "%s():%d Unsupported IOCTL:%x \n", __func__, __LINE__, cmd); | |
463 | + ret = -ENOTTY; | |
464 | + break; | |
465 | + } | |
466 | + spin_unlock(&vcd->vcd_cdrom_info_lock); | |
467 | +out: | |
468 | + return ret; | |
469 | +} | |
470 | + | |
471 | +/* Called as result of cdrom_open, vcd_cdrom_info_lock already held */ | |
472 | +static int xencdrom_block_media_changed(struct gendisk *disk) | |
473 | +{ | |
474 | + struct vcd_disk * vcd; | |
475 | + struct vcd_disk * ret_vcd = NULL; | |
476 | + int ret = 0; | |
477 | + | |
478 | + spin_lock(&vcd_disks_lock); | |
479 | + list_for_each_entry(vcd, &vcd_disks, vcd_entry) { | |
480 | + if (vcd->vcd_cdrom_info.disk == disk) { | |
481 | + ret_vcd = vcd; | |
482 | + break; | |
483 | + } | |
484 | + } | |
485 | + spin_unlock(&vcd_disks_lock); | |
486 | + if (ret_vcd) { | |
487 | + ret = cdrom_media_changed(&ret_vcd->vcd_cdrom_info); | |
488 | + } | |
489 | + return ret; | |
490 | +} | |
491 | + | |
492 | +static struct block_device_operations xencdrom_bdops = | |
493 | +{ | |
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, | |
499 | +}; | |
500 | + | |
501 | +void register_vcd(struct blkfront_info *info) | |
502 | +{ | |
503 | + struct gendisk * gd = info->gd; | |
504 | + struct vcd_disk * vcd; | |
505 | + | |
506 | + /* Make sure this is for a CD device */ | |
507 | + if (!(gd->flags & GENHD_FL_CD)) | |
508 | + goto out; | |
509 | + | |
510 | + /* Make sure we have backend support */ | |
511 | + if (!xencdrom_supported(info)) { | |
512 | + goto out; | |
513 | + } | |
514 | + | |
515 | + /* Create new vcd_disk and fill in cdrom_info */ | |
516 | + vcd = (struct vcd_disk *)kzalloc(sizeof(struct vcd_disk), GFP_KERNEL); | |
517 | + if (!vcd) { | |
518 | + printk(KERN_INFO "%s(): Unable to allocate vcd struct!\n", __func__); | |
519 | + goto out; | |
520 | + } | |
521 | + spin_lock_init(&vcd->vcd_cdrom_info_lock); | |
522 | + | |
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); | |
531 | + | |
532 | + if (register_cdrom(&(vcd->vcd_cdrom_info)) != 0) { | |
533 | + printk(KERN_WARNING "%s() Cannot register blkdev as a cdrom %d!\n", __func__, | |
534 | + gd->major); | |
535 | + goto err_out; | |
536 | + } | |
537 | + xencdrom_bdops.owner = gd->fops->owner; | |
538 | + gd->fops = &xencdrom_bdops; | |
539 | + vcd->vcd_cdrom_info.disk = gd; | |
540 | + | |
541 | + spin_lock(&vcd_disks_lock); | |
542 | + list_add(&(vcd->vcd_entry), &vcd_disks); | |
543 | + spin_unlock(&vcd_disks_lock); | |
544 | +out: | |
545 | + return; | |
546 | +err_out: | |
547 | + kfree(vcd); | |
548 | +} | |
549 | + | |
550 | +void unregister_vcd(struct blkfront_info *info) { | |
551 | + struct gendisk * gd = info->gd; | |
552 | + struct vcd_disk * vcd; | |
553 | + | |
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); | |
561 | + kfree(vcd); | |
562 | + break; | |
563 | + } | |
564 | + } | |
565 | + spin_unlock(&vcd_disks_lock); | |
566 | +} | |
567 | + | |
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 | |
572 | @@ -0,0 +1,120 @@ | |
573 | +/****************************************************************************** | |
574 | + * cdromif.h | |
575 | + * | |
576 | + * Shared definitions between backend driver and Xen guest Virtual CDROM | |
577 | + * block device. | |
578 | + * | |
579 | + * Copyright (c) 2008, Pat Campell plc@novell.com | |
580 | + * | |
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: | |
587 | + * | |
588 | + * The above copyright notice and this permission notice shall be included in | |
589 | + * all copies or substantial portions of the Software. | |
590 | + * | |
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 | |
597 | + * IN THE SOFTWARE. | |
598 | + */ | |
599 | + | |
600 | +#ifndef __XEN_PUBLIC_IO_CDROMIF_H__ | |
601 | +#define __XEN_PUBLIC_IO_CDROMIF_H__ | |
602 | + | |
603 | +/* | |
604 | + * Queries backend for CDROM support | |
605 | + */ | |
606 | +#define XEN_TYPE_CDROM_SUPPORT _IO('c', 1) | |
607 | + | |
608 | +struct xen_cdrom_support | |
609 | +{ | |
610 | + uint32_t type; | |
611 | + int8_t ret; /* returned, 0 succeded, -1 error */ | |
612 | + int8_t err; /* returned, backend errno */ | |
613 | + int8_t supported; /* returned, 1 supported */ | |
614 | +}; | |
615 | + | |
616 | +/* | |
617 | + * Opens backend device, returns drive geometry or | |
618 | + * any encountered errors | |
619 | + */ | |
620 | +#define XEN_TYPE_CDROM_OPEN _IO('c', 2) | |
621 | + | |
622 | +struct xen_cdrom_open | |
623 | +{ | |
624 | + uint32_t type; | |
625 | + int8_t ret; | |
626 | + int8_t err; | |
627 | + int8_t pad; | |
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 */ | |
632 | +}; | |
633 | + | |
634 | +/* | |
635 | + * Queries backend for media changed status | |
636 | + */ | |
637 | +#define XEN_TYPE_CDROM_MEDIA_CHANGED _IO('c', 3) | |
638 | + | |
639 | +struct xen_cdrom_media_changed | |
640 | +{ | |
641 | + uint32_t type; | |
642 | + int8_t ret; | |
643 | + int8_t err; | |
644 | + int8_t media_changed; /* returned */ | |
645 | +}; | |
646 | + | |
647 | +/* | |
648 | + * Sends vcd generic CDROM packet to backend, followed | |
649 | + * immediately by the vcd_generic_command payload | |
650 | + */ | |
651 | +#define XEN_TYPE_CDROM_PACKET _IO('c', 4) | |
652 | + | |
653 | +struct xen_cdrom_packet | |
654 | +{ | |
655 | + uint32_t type; | |
656 | + int8_t ret; | |
657 | + int8_t err; | |
658 | + int8_t pad[2]; | |
659 | + int32_t payload_offset; /* offset to vcd_generic_command payload */ | |
660 | +}; | |
661 | + | |
662 | +/* CDROM_PACKET_COMMAND, payload for XEN_TYPE_CDROM_PACKET */ | |
663 | +struct vcd_generic_command | |
664 | +{ | |
665 | + uint8_t cmd[CDROM_PACKET_SIZE]; | |
666 | + uint8_t pad[4]; | |
667 | + uint32_t buffer_offset; | |
668 | + uint32_t buflen; | |
669 | + int32_t stat; | |
670 | + uint32_t sense_offset; | |
671 | + uint8_t data_direction; | |
672 | + uint8_t pad1[3]; | |
673 | + int32_t quiet; | |
674 | + int32_t timeout; | |
675 | +}; | |
676 | + | |
677 | +union xen_block_packet | |
678 | +{ | |
679 | + uint32_t type; | |
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; | |
684 | +}; | |
685 | + | |
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)) | |
691 | + | |
692 | +#endif |