drivers/block/virtio_blk.c | 36 +++++++++++++++++++++++++++++++++---
include/linux/virtio_blk.h | 10 ++++++++++
2 files changed, 43 insertions(+), 3 deletions(-)
=================================================================
@@ -14,7 +14,16 @@
#define VIRTIO_BLK_F_GEOMETRY 4 /* Legacy geometry available */
#define VIRTIO_BLK_F_RO 5 /* Disk is read-only */
#define VIRTIO_BLK_F_BLK_SIZE 6 /* Block size of disk is available*/
+#define VIRTIO_BLK_F_SN 7 /* serial number supported */
+/* ioctl cmd to retrieve serial#
+*/
+#define VBLK_GET_SN ((unsigned int)('V' << 24 | 'B' << 16 | 'L' << 8 | 'K'))
+
+#define BLOCK_SERIAL_STRLEN 20
+
+/* mapped into pci i/o region 0
+ */
struct virtio_blk_config
{
/* The capacity (in 512-byte sectors). */
@@ -31,6 +40,7 @@ struct virtio_blk_config
} geometry;
/* block size of device (if VIRTIO_BLK_F_BLK_SIZE) */
__u32 blk_size;
+ __u8 serial[BLOCK_SERIAL_STRLEN];
} __attribute__((packed));
/* These two define direction. */
=================================================================
@@ -146,12 +146,41 @@ static void do_virtblk_request(struct re
vblk->vq->vq_ops->kick(vblk->vq);
}
+/* user passes the address of a char[] for serial# return, and has set char[0]
+ * to the array size. copy serial# to this char[] and return number of
+ * characters copied excluding any trailing '\0' pad chars in buffer.
+ */
+#define _min(a,b) ((a) < (b) ? (a) : (b))
+static int get_virtblk_sn(struct block_device *bdev, void *buf)
+{
+ struct virtio_blk *vblk = bdev->bd_disk->private_data;
+ unsigned char serial[BLOCK_SERIAL_STRLEN];
+ unsigned char snlen;
+ int rv;
+
+ if (copy_from_user(&snlen, buf, sizeof (snlen)))
+ rv = -EFAULT;
+ else if ((rv = virtio_config_val(vblk->vdev, VIRTIO_BLK_F_SN,
+ offsetof(struct virtio_blk_config, serial), &serial)))
+ ;
+ else if (copy_to_user(buf, serial,
+ snlen = min(snlen, (unsigned char)sizeof (serial))))
+ rv = -EFAULT;
+ else
+ for (rv = 0; rv < snlen; ++rv)
+ if (!serial[rv])
+ break;
+ return (rv);
+}
+
static int virtblk_ioctl(struct block_device *bdev, fmode_t mode,
unsigned cmd, unsigned long data)
{
- return scsi_cmd_ioctl(bdev->bd_disk->queue,
- bdev->bd_disk, mode, cmd,
- (void __user *)data);
+ if (cmd == VBLK_GET_SN)
+ return (get_virtblk_sn(bdev, (void __user *)data));
+ else
+ return scsi_cmd_ioctl(bdev->bd_disk->queue, bdev->bd_disk,
+ mode, cmd, (void __user *)data);
}
/* We provide getgeo only to please some old bootloader/partitioning tools */
@@ -339,6 +368,7 @@ static struct virtio_device_id id_table[
static unsigned int features[] = {
VIRTIO_BLK_F_BARRIER, VIRTIO_BLK_F_SEG_MAX, VIRTIO_BLK_F_SIZE_MAX,
VIRTIO_BLK_F_GEOMETRY, VIRTIO_BLK_F_RO, VIRTIO_BLK_F_BLK_SIZE,
+ VIRTIO_BLK_F_SN
};
static struct virtio_driver virtio_blk = {