+ struct disk_info *d;
+ struct cdrom_device_info *c;
+ struct cdrom_info *ci;
+ struct request_queue *q;
+
+ deviceno = vdev->unit_address;
+ if (deviceno >= viocd_numdev)
+ return -ENODEV;
+
+ d = &viocd_diskinfo[deviceno];
+ c = &d->viocd_info;
+ ci = &viocd_unitinfo[deviceno];
+
+ c->ops = &viocd_dops;
+ c->speed = 4;
+ c->capacity = 1;
+ c->handle = d;
+ c->mask = ~find_capability(ci->type);
+ sprintf(c->name, VIOCD_DEVICE "%c", 'a' + deviceno);
+
+ if (register_cdrom(c) != 0) {
+ printk(VIOCD_KERN_WARNING "Cannot register viocd CD-ROM %s!\n",
+ c->name);
+ goto out;
+ }
+ printk(VIOCD_KERN_INFO "cd %s is iSeries resource %10.10s "
+ "type %4.4s, model %3.3s\n",
+ c->name, ci->rsrcname, ci->type, ci->model);
+ q = blk_init_queue(do_viocd_request, &viocd_reqlock);
+ if (q == NULL) {
+ printk(VIOCD_KERN_WARNING "Cannot allocate queue for %s!\n",
+ c->name);
+ goto out_unregister_cdrom;
+ }
+ gendisk = alloc_disk(1);
+ if (gendisk == NULL) {
+ printk(VIOCD_KERN_WARNING "Cannot create gendisk for %s!\n",
+ c->name);
+ goto out_cleanup_queue;
+ }
+ gendisk->major = VIOCD_MAJOR;
+ gendisk->first_minor = deviceno;
+ strncpy(gendisk->disk_name, c->name,
+ sizeof(gendisk->disk_name));
+ blk_queue_max_hw_segments(q, 1);
+ blk_queue_max_phys_segments(q, 1);
+ blk_queue_max_sectors(q, 4096 / 512);
+ gendisk->queue = q;
+ gendisk->fops = &viocd_fops;
+ gendisk->flags = GENHD_FL_CD|GENHD_FL_REMOVABLE;
+ set_capacity(gendisk, 0);
+ gendisk->private_data = d;
+ d->viocd_disk = gendisk;
+ d->dev = &vdev->dev;
+ gendisk->driverfs_dev = d->dev;
+ add_disk(gendisk);
+ return 0;
+
+out_cleanup_queue:
+ blk_cleanup_queue(q);
+out_unregister_cdrom:
+ unregister_cdrom(c);
+out:
+ return -ENODEV;
+}
+
+static int viocd_remove(struct vio_dev *vdev)
+{
+ struct disk_info *d = &viocd_diskinfo[vdev->unit_address];
+
+ if (unregister_cdrom(&d->viocd_info) != 0)
+ printk(VIOCD_KERN_WARNING
+ "Cannot unregister viocd CD-ROM %s!\n",
+ d->viocd_info.name);
+ del_gendisk(d->viocd_disk);
+ blk_cleanup_queue(d->viocd_disk->queue);
+ put_disk(d->viocd_disk);
+ return 0;
+}
+
+/**
+ * viocd_device_table: Used by vio.c to match devices that we
+ * support.
+ */
+static struct vio_device_id viocd_device_table[] __devinitdata = {
+ { "block", "IBM,iSeries-viocd" },
+ { "", "" }
+};
+MODULE_DEVICE_TABLE(vio, viocd_device_table);
+
+static struct vio_driver viocd_driver = {
+ .id_table = viocd_device_table,
+ .probe = viocd_probe,
+ .remove = viocd_remove,
+ .driver = {
+ .name = "viocd",
+ .owner = THIS_MODULE,
+ }
+};
+
+static int __init viocd_init(void)
+{