Commit bf011293faaa7f87e4de83185931e7411b794128

Authored by john cooper
Committed by Anthony Liguori
1 parent 024589f1

Add serial number support for virtio_blk

[brought forward to current qemu-kvm.git]

This patch implements the missing qemu logic to
interpret a '-drive .. serial=XYZ ..' flag for
a virtio_blk device.

The serial number string is contained in a
skeletal IDENTIFY DEVICE data structure and
this structure is made available to the guest
virtio_blk driver via pci i/o region 0.

Signed-off-by: john cooper <john.cooper@redhat.com>
Signed-off-by: Anthony Liguori <aliguori@us.ibm.com>
hw/virtio-blk.c
@@ -25,6 +25,7 @@ typedef struct VirtIOBlock @@ -25,6 +25,7 @@ typedef struct VirtIOBlock
25 BlockDriverState *bs; 25 BlockDriverState *bs;
26 VirtQueue *vq; 26 VirtQueue *vq;
27 void *rq; 27 void *rq;
  28 + char serial_str[BLOCK_SERIAL_STRLEN + 1];
28 } VirtIOBlock; 29 } VirtIOBlock;
29 30
30 static VirtIOBlock *to_virtio_blk(VirtIODevice *vdev) 31 static VirtIOBlock *to_virtio_blk(VirtIODevice *vdev)
@@ -32,6 +33,47 @@ static VirtIOBlock *to_virtio_blk(VirtIODevice *vdev) @@ -32,6 +33,47 @@ static VirtIOBlock *to_virtio_blk(VirtIODevice *vdev)
32 return (VirtIOBlock *)vdev; 33 return (VirtIOBlock *)vdev;
33 } 34 }
34 35
  36 +/* store identify data in little endian format
  37 + */
  38 +static inline void put_le16(uint16_t *p, unsigned int v)
  39 +{
  40 + *p = cpu_to_le16(v);
  41 +}
  42 +
  43 +/* copy to *dst from *src, nul pad dst tail as needed to len bytes
  44 + */
  45 +static inline void padstr(char *dst, const char *src, int len)
  46 +{
  47 + while (len--)
  48 + *dst++ = *src ? *src++ : '\0';
  49 +}
  50 +
  51 +/* setup simulated identify data as appropriate for virtio block device
  52 + *
  53 + * ref: AT Attachment 8 - ATA/ATAPI Command Set (ATA8-ACS)
  54 + */
  55 +static inline void virtio_identify_template(struct virtio_blk_config *bc)
  56 +{
  57 + uint16_t *p = &bc->identify[0];
  58 + uint64_t lba_sectors = bc->capacity;
  59 +
  60 + memset(p, 0, sizeof(bc->identify));
  61 + put_le16(p + 0, 0x0); /* ATA device */
  62 + padstr((char *)(p + 23), QEMU_VERSION, 8); /* firmware revision */
  63 + padstr((char *)(p + 27), "QEMU VIRT_BLK", 40); /* model# */
  64 + put_le16(p + 47, 0x80ff); /* max xfer 255 sectors */
  65 + put_le16(p + 49, 0x0b00); /* support IORDY/LBA/DMA */
  66 + put_le16(p + 59, 0x1ff); /* cur xfer 255 sectors */
  67 + put_le16(p + 80, 0x1f0); /* support ATA8/7/6/5/4 */
  68 + put_le16(p + 81, 0x16);
  69 + put_le16(p + 82, 0x400);
  70 + put_le16(p + 83, 0x400);
  71 + put_le16(p + 100, lba_sectors);
  72 + put_le16(p + 101, lba_sectors >> 16);
  73 + put_le16(p + 102, lba_sectors >> 32);
  74 + put_le16(p + 103, lba_sectors >> 48);
  75 +}
  76 +
35 typedef struct VirtIOBlockReq 77 typedef struct VirtIOBlockReq
36 { 78 {
37 VirtIOBlock *dev; 79 VirtIOBlock *dev;
@@ -285,6 +327,8 @@ static void virtio_blk_reset(VirtIODevice *vdev) @@ -285,6 +327,8 @@ static void virtio_blk_reset(VirtIODevice *vdev)
285 qemu_aio_flush(); 327 qemu_aio_flush();
286 } 328 }
287 329
  330 +/* coalesce internal state, copy to pci i/o region 0
  331 + */
288 static void virtio_blk_update_config(VirtIODevice *vdev, uint8_t *config) 332 static void virtio_blk_update_config(VirtIODevice *vdev, uint8_t *config)
289 { 333 {
290 VirtIOBlock *s = to_virtio_blk(vdev); 334 VirtIOBlock *s = to_virtio_blk(vdev);
@@ -301,11 +345,15 @@ static void virtio_blk_update_config(VirtIODevice *vdev, uint8_t *config) @@ -301,11 +345,15 @@ static void virtio_blk_update_config(VirtIODevice *vdev, uint8_t *config)
301 blkcfg.heads = heads; 345 blkcfg.heads = heads;
302 blkcfg.sectors = secs; 346 blkcfg.sectors = secs;
303 blkcfg.size_max = 0; 347 blkcfg.size_max = 0;
  348 + virtio_identify_template(&blkcfg);
  349 + memcpy(&blkcfg.identify[VIRTIO_BLK_ID_SN], s->serial_str,
  350 + VIRTIO_BLK_ID_SN_BYTES);
304 memcpy(config, &blkcfg, sizeof(blkcfg)); 351 memcpy(config, &blkcfg, sizeof(blkcfg));
305 } 352 }
306 353
307 static uint32_t virtio_blk_get_features(VirtIODevice *vdev) 354 static uint32_t virtio_blk_get_features(VirtIODevice *vdev)
308 { 355 {
  356 + VirtIOBlock *s = to_virtio_blk(vdev);
309 uint32_t features = 0; 357 uint32_t features = 0;
310 358
311 features |= (1 << VIRTIO_BLK_F_SEG_MAX); 359 features |= (1 << VIRTIO_BLK_F_SEG_MAX);
@@ -313,6 +361,8 @@ static uint32_t virtio_blk_get_features(VirtIODevice *vdev) @@ -313,6 +361,8 @@ static uint32_t virtio_blk_get_features(VirtIODevice *vdev)
313 #ifdef __linux__ 361 #ifdef __linux__
314 features |= (1 << VIRTIO_BLK_F_SCSI); 362 features |= (1 << VIRTIO_BLK_F_SCSI);
315 #endif 363 #endif
  364 + if (strcmp(s->serial_str, "0"))
  365 + features |= 1 << VIRTIO_BLK_F_IDENTIFY;
316 366
317 return features; 367 return features;
318 } 368 }
@@ -356,6 +406,7 @@ VirtIODevice *virtio_blk_init(DeviceState *dev) @@ -356,6 +406,7 @@ VirtIODevice *virtio_blk_init(DeviceState *dev)
356 int cylinders, heads, secs; 406 int cylinders, heads, secs;
357 static int virtio_blk_id; 407 static int virtio_blk_id;
358 BlockDriverState *bs; 408 BlockDriverState *bs;
  409 + char *ps;
359 410
360 s = (VirtIOBlock *)virtio_common_init("virtio-blk", VIRTIO_ID_BLOCK, 411 s = (VirtIOBlock *)virtio_common_init("virtio-blk", VIRTIO_ID_BLOCK,
361 sizeof(struct virtio_blk_config), 412 sizeof(struct virtio_blk_config),
@@ -367,6 +418,10 @@ VirtIODevice *virtio_blk_init(DeviceState *dev) @@ -367,6 +418,10 @@ VirtIODevice *virtio_blk_init(DeviceState *dev)
367 s->vdev.reset = virtio_blk_reset; 418 s->vdev.reset = virtio_blk_reset;
368 s->bs = bs; 419 s->bs = bs;
369 s->rq = NULL; 420 s->rq = NULL;
  421 + if (strlen(ps = (char *)drive_get_serial(bs)))
  422 + strncpy(s->serial_str, ps, sizeof(s->serial_str));
  423 + else
  424 + snprintf(s->serial_str, sizeof(s->serial_str), "0");
370 bs->private = dev; 425 bs->private = dev;
371 bdrv_guess_geometry(s->bs, &cylinders, &heads, &secs); 426 bdrv_guess_geometry(s->bs, &cylinders, &heads, &secs);
372 bdrv_set_geometry_hint(s->bs, cylinders, heads, secs); 427 bdrv_set_geometry_hint(s->bs, cylinders, heads, secs);
hw/virtio-blk.h
@@ -30,6 +30,11 @@ @@ -30,6 +30,11 @@
30 #define VIRTIO_BLK_F_RO 5 /* Disk is read-only */ 30 #define VIRTIO_BLK_F_RO 5 /* Disk is read-only */
31 #define VIRTIO_BLK_F_BLK_SIZE 6 /* Block size of disk is available*/ 31 #define VIRTIO_BLK_F_BLK_SIZE 6 /* Block size of disk is available*/
32 #define VIRTIO_BLK_F_SCSI 7 /* Supports scsi command passthru */ 32 #define VIRTIO_BLK_F_SCSI 7 /* Supports scsi command passthru */
  33 +#define VIRTIO_BLK_F_IDENTIFY 8 /* ATA IDENTIFY supported */
  34 +
  35 +#define VIRTIO_BLK_ID_LEN 256 /* length of identify u16 array */
  36 +#define VIRTIO_BLK_ID_SN 10 /* start of char * serial# */
  37 +#define VIRTIO_BLK_ID_SN_BYTES 20 /* length in bytes of serial# */
33 38
34 struct virtio_blk_config 39 struct virtio_blk_config
35 { 40 {
@@ -39,6 +44,8 @@ struct virtio_blk_config @@ -39,6 +44,8 @@ struct virtio_blk_config
39 uint16_t cylinders; 44 uint16_t cylinders;
40 uint8_t heads; 45 uint8_t heads;
41 uint8_t sectors; 46 uint8_t sectors;
  47 + uint32_t _blk_size; /* structure pad, currently unused */
  48 + uint16_t identify[VIRTIO_BLK_ID_LEN];
42 } __attribute__((packed)); 49 } __attribute__((packed));
43 50
44 /* These two define direction. */ 51 /* These two define direction. */
sysemu.h
@@ -154,6 +154,8 @@ typedef enum { @@ -154,6 +154,8 @@ typedef enum {
154 BLOCK_ERR_STOP_ANY 154 BLOCK_ERR_STOP_ANY
155 } BlockInterfaceErrorAction; 155 } BlockInterfaceErrorAction;
156 156
  157 +#define BLOCK_SERIAL_STRLEN 20
  158 +
157 typedef struct DriveInfo { 159 typedef struct DriveInfo {
158 BlockDriverState *bdrv; 160 BlockDriverState *bdrv;
159 const char *devaddr; 161 const char *devaddr;
@@ -163,7 +165,7 @@ typedef struct DriveInfo { @@ -163,7 +165,7 @@ typedef struct DriveInfo {
163 int used; 165 int used;
164 int drive_opt_idx; 166 int drive_opt_idx;
165 BlockInterfaceErrorAction onerror; 167 BlockInterfaceErrorAction onerror;
166 - char serial[21]; 168 + char serial[BLOCK_SERIAL_STRLEN + 1];
167 } DriveInfo; 169 } DriveInfo;
168 170
169 #define MAX_IDE_DEVS 2 171 #define MAX_IDE_DEVS 2