aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/block
diff options
context:
space:
mode:
authorAllen Pais <allen.pais@oracle.com>2014-09-19 09:42:14 -0400
committerDavid S. Miller <davem@davemloft.net>2014-09-30 17:37:34 -0400
commit9bce21828d54a95143f1b74619705c2dd8e88b92 (patch)
tree6565bfb1f8c3cfa6f307bb8600d11eab0fd5d20f /drivers/block
parent163a4e7473061388bba0899a1a063bae44e1715a (diff)
sunvdc: add cdrom and v1.1 protocol support
Interpret the media type from v1.1 protocol to support CDROM/DVD. For v1.0 protocol, a disk's size continues to be calculated from the geometry returned by the vdisk server. The geometry returned by the server can be less than the actual number of sectors available in the backing image/device due to the rounding in the division used to compute the geometry in the vdisk server. In v1.1 protocol a disk's actual size in sectors is returned during the handshake. Use this size when v1.1 protocol is negotiated. Since this size will always be larger than the former geometry computed size, disks created under v1.0 will be forwards compatible to v1.1, but not vice versa. Signed-off-by: Dwight Engen <dwight.engen@oracle.com> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers/block')
-rw-r--r--drivers/block/sunvdc.c109
1 files changed, 92 insertions, 17 deletions
diff --git a/drivers/block/sunvdc.c b/drivers/block/sunvdc.c
index 5814deb6963d..66ddf704ad7f 100644
--- a/drivers/block/sunvdc.c
+++ b/drivers/block/sunvdc.c
@@ -9,6 +9,7 @@
9#include <linux/blkdev.h> 9#include <linux/blkdev.h>
10#include <linux/hdreg.h> 10#include <linux/hdreg.h>
11#include <linux/genhd.h> 11#include <linux/genhd.h>
12#include <linux/cdrom.h>
12#include <linux/slab.h> 13#include <linux/slab.h>
13#include <linux/spinlock.h> 14#include <linux/spinlock.h>
14#include <linux/completion.h> 15#include <linux/completion.h>
@@ -22,8 +23,8 @@
22 23
23#define DRV_MODULE_NAME "sunvdc" 24#define DRV_MODULE_NAME "sunvdc"
24#define PFX DRV_MODULE_NAME ": " 25#define PFX DRV_MODULE_NAME ": "
25#define DRV_MODULE_VERSION "1.0" 26#define DRV_MODULE_VERSION "1.1"
26#define DRV_MODULE_RELDATE "June 25, 2007" 27#define DRV_MODULE_RELDATE "February 13, 2013"
27 28
28static char version[] = 29static char version[] =
29 DRV_MODULE_NAME ".c:v" DRV_MODULE_VERSION " (" DRV_MODULE_RELDATE ")\n"; 30 DRV_MODULE_NAME ".c:v" DRV_MODULE_VERSION " (" DRV_MODULE_RELDATE ")\n";
@@ -65,6 +66,7 @@ struct vdc_port {
65 u64 operations; 66 u64 operations;
66 u32 vdisk_size; 67 u32 vdisk_size;
67 u8 vdisk_type; 68 u8 vdisk_type;
69 u8 vdisk_mtype;
68 70
69 char disk_name[32]; 71 char disk_name[32];
70 72
@@ -79,9 +81,16 @@ static inline struct vdc_port *to_vdc_port(struct vio_driver_state *vio)
79 81
80/* Ordered from largest major to lowest */ 82/* Ordered from largest major to lowest */
81static struct vio_version vdc_versions[] = { 83static struct vio_version vdc_versions[] = {
84 { .major = 1, .minor = 1 },
82 { .major = 1, .minor = 0 }, 85 { .major = 1, .minor = 0 },
83}; 86};
84 87
88static inline int vdc_version_supported(struct vdc_port *port,
89 u16 major, u16 minor)
90{
91 return port->vio.ver.major == major && port->vio.ver.minor >= minor;
92}
93
85#define VDCBLK_NAME "vdisk" 94#define VDCBLK_NAME "vdisk"
86static int vdc_major; 95static int vdc_major;
87#define PARTITION_SHIFT 3 96#define PARTITION_SHIFT 3
@@ -103,9 +112,41 @@ static int vdc_getgeo(struct block_device *bdev, struct hd_geometry *geo)
103 return 0; 112 return 0;
104} 113}
105 114
115/* Add ioctl/CDROM_GET_CAPABILITY to support cdrom_id in udev
116 * when vdisk_mtype is VD_MEDIA_TYPE_CD or VD_MEDIA_TYPE_DVD.
117 * Needed to be able to install inside an ldom from an iso image.
118 */
119static int vdc_ioctl(struct block_device *bdev, fmode_t mode,
120 unsigned command, unsigned long argument)
121{
122 int i;
123 struct gendisk *disk;
124
125 switch (command) {
126 case CDROMMULTISESSION:
127 pr_debug(PFX "Multisession CDs not supported\n");
128 for (i = 0; i < sizeof(struct cdrom_multisession); i++)
129 if (put_user(0, (char __user *)(argument + i)))
130 return -EFAULT;
131 return 0;
132
133 case CDROM_GET_CAPABILITY:
134 disk = bdev->bd_disk;
135
136 if (bdev->bd_disk && (disk->flags & GENHD_FL_CD))
137 return 0;
138 return -EINVAL;
139
140 default:
141 pr_debug(PFX "ioctl %08x not supported\n", command);
142 return -EINVAL;
143 }
144}
145
106static const struct block_device_operations vdc_fops = { 146static const struct block_device_operations vdc_fops = {
107 .owner = THIS_MODULE, 147 .owner = THIS_MODULE,
108 .getgeo = vdc_getgeo, 148 .getgeo = vdc_getgeo,
149 .ioctl = vdc_ioctl,
109}; 150};
110 151
111static void vdc_finish(struct vio_driver_state *vio, int err, int waiting_for) 152static void vdc_finish(struct vio_driver_state *vio, int err, int waiting_for)
@@ -165,9 +206,9 @@ static int vdc_handle_attr(struct vio_driver_state *vio, void *arg)
165 struct vio_disk_attr_info *pkt = arg; 206 struct vio_disk_attr_info *pkt = arg;
166 207
167 viodbg(HS, "GOT ATTR stype[0x%x] ops[%llx] disk_size[%llu] disk_type[%x] " 208 viodbg(HS, "GOT ATTR stype[0x%x] ops[%llx] disk_size[%llu] disk_type[%x] "
168 "xfer_mode[0x%x] blksz[%u] max_xfer[%llu]\n", 209 "mtype[0x%x] xfer_mode[0x%x] blksz[%u] max_xfer[%llu]\n",
169 pkt->tag.stype, pkt->operations, 210 pkt->tag.stype, pkt->operations,
170 pkt->vdisk_size, pkt->vdisk_type, 211 pkt->vdisk_size, pkt->vdisk_type, pkt->vdisk_mtype,
171 pkt->xfer_mode, pkt->vdisk_block_size, 212 pkt->xfer_mode, pkt->vdisk_block_size,
172 pkt->max_xfer_size); 213 pkt->max_xfer_size);
173 214
@@ -192,8 +233,11 @@ static int vdc_handle_attr(struct vio_driver_state *vio, void *arg)
192 } 233 }
193 234
194 port->operations = pkt->operations; 235 port->operations = pkt->operations;
195 port->vdisk_size = pkt->vdisk_size;
196 port->vdisk_type = pkt->vdisk_type; 236 port->vdisk_type = pkt->vdisk_type;
237 if (vdc_version_supported(port, 1, 1)) {
238 port->vdisk_size = pkt->vdisk_size;
239 port->vdisk_mtype = pkt->vdisk_mtype;
240 }
197 if (pkt->max_xfer_size < port->max_xfer_size) 241 if (pkt->max_xfer_size < port->max_xfer_size)
198 port->max_xfer_size = pkt->max_xfer_size; 242 port->max_xfer_size = pkt->max_xfer_size;
199 port->vdisk_block_size = pkt->vdisk_block_size; 243 port->vdisk_block_size = pkt->vdisk_block_size;
@@ -663,18 +707,25 @@ static int probe_disk(struct vdc_port *port)
663 return err; 707 return err;
664 } 708 }
665 709
666 err = generic_request(port, VD_OP_GET_DISKGEOM, 710 if (vdc_version_supported(port, 1, 1)) {
667 &port->geom, sizeof(port->geom)); 711 /* vdisk_size should be set during the handshake, if it wasn't
668 if (err < 0) { 712 * then the underlying disk is reserved by another system
669 printk(KERN_ERR PFX "VD_OP_GET_DISKGEOM returns " 713 */
670 "error %d\n", err); 714 if (port->vdisk_size == -1)
671 return err; 715 return -ENODEV;
716 } else {
717 err = generic_request(port, VD_OP_GET_DISKGEOM,
718 &port->geom, sizeof(port->geom));
719 if (err < 0) {
720 printk(KERN_ERR PFX "VD_OP_GET_DISKGEOM returns "
721 "error %d\n", err);
722 return err;
723 }
724 port->vdisk_size = ((u64)port->geom.num_cyl *
725 (u64)port->geom.num_hd *
726 (u64)port->geom.num_sec);
672 } 727 }
673 728
674 port->vdisk_size = ((u64)port->geom.num_cyl *
675 (u64)port->geom.num_hd *
676 (u64)port->geom.num_sec);
677
678 q = blk_init_queue(do_vdc_request, &port->vio.lock); 729 q = blk_init_queue(do_vdc_request, &port->vio.lock);
679 if (!q) { 730 if (!q) {
680 printk(KERN_ERR PFX "%s: Could not allocate queue.\n", 731 printk(KERN_ERR PFX "%s: Could not allocate queue.\n",
@@ -704,9 +755,32 @@ static int probe_disk(struct vdc_port *port)
704 755
705 set_capacity(g, port->vdisk_size); 756 set_capacity(g, port->vdisk_size);
706 757
707 printk(KERN_INFO PFX "%s: %u sectors (%u MB)\n", 758 if (vdc_version_supported(port, 1, 1)) {
759 switch (port->vdisk_mtype) {
760 case VD_MEDIA_TYPE_CD:
761 pr_info(PFX "Virtual CDROM %s\n", port->disk_name);
762 g->flags |= GENHD_FL_CD;
763 g->flags |= GENHD_FL_REMOVABLE;
764 set_disk_ro(g, 1);
765 break;
766
767 case VD_MEDIA_TYPE_DVD:
768 pr_info(PFX "Virtual DVD %s\n", port->disk_name);
769 g->flags |= GENHD_FL_CD;
770 g->flags |= GENHD_FL_REMOVABLE;
771 set_disk_ro(g, 1);
772 break;
773
774 case VD_MEDIA_TYPE_FIXED:
775 pr_info(PFX "Virtual Hard disk %s\n", port->disk_name);
776 break;
777 }
778 }
779
780 pr_info(PFX "%s: %u sectors (%u MB) protocol %d.%d\n",
708 g->disk_name, 781 g->disk_name,
709 port->vdisk_size, (port->vdisk_size >> (20 - 9))); 782 port->vdisk_size, (port->vdisk_size >> (20 - 9)),
783 port->vio.ver.major, port->vio.ver.minor);
710 784
711 add_disk(g); 785 add_disk(g);
712 786
@@ -765,6 +839,7 @@ static int vdc_port_probe(struct vio_dev *vdev, const struct vio_device_id *id)
765 else 839 else
766 snprintf(port->disk_name, sizeof(port->disk_name), 840 snprintf(port->disk_name, sizeof(port->disk_name),
767 VDCBLK_NAME "%c", 'a' + ((int)vdev->dev_no % 26)); 841 VDCBLK_NAME "%c", 'a' + ((int)vdev->dev_no % 26));
842 port->vdisk_size = -1;
768 843
769 err = vio_driver_init(&port->vio, vdev, VDEV_DISK, 844 err = vio_driver_init(&port->vio, vdev, VDEV_DISK,
770 vdc_versions, ARRAY_SIZE(vdc_versions), 845 vdc_versions, ARRAY_SIZE(vdc_versions),