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 25 BlockDriverState *bs;
26 26 VirtQueue *vq;
27 27 void *rq;
  28 + char serial_str[BLOCK_SERIAL_STRLEN + 1];
28 29 } VirtIOBlock;
29 30  
30 31 static VirtIOBlock *to_virtio_blk(VirtIODevice *vdev)
... ... @@ -32,6 +33,47 @@ static VirtIOBlock *to_virtio_blk(VirtIODevice *vdev)
32 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 77 typedef struct VirtIOBlockReq
36 78 {
37 79 VirtIOBlock *dev;
... ... @@ -285,6 +327,8 @@ static void virtio_blk_reset(VirtIODevice *vdev)
285 327 qemu_aio_flush();
286 328 }
287 329  
  330 +/* coalesce internal state, copy to pci i/o region 0
  331 + */
288 332 static void virtio_blk_update_config(VirtIODevice *vdev, uint8_t *config)
289 333 {
290 334 VirtIOBlock *s = to_virtio_blk(vdev);
... ... @@ -301,11 +345,15 @@ static void virtio_blk_update_config(VirtIODevice *vdev, uint8_t *config)
301 345 blkcfg.heads = heads;
302 346 blkcfg.sectors = secs;
303 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 351 memcpy(config, &blkcfg, sizeof(blkcfg));
305 352 }
306 353  
307 354 static uint32_t virtio_blk_get_features(VirtIODevice *vdev)
308 355 {
  356 + VirtIOBlock *s = to_virtio_blk(vdev);
309 357 uint32_t features = 0;
310 358  
311 359 features |= (1 << VIRTIO_BLK_F_SEG_MAX);
... ... @@ -313,6 +361,8 @@ static uint32_t virtio_blk_get_features(VirtIODevice *vdev)
313 361 #ifdef __linux__
314 362 features |= (1 << VIRTIO_BLK_F_SCSI);
315 363 #endif
  364 + if (strcmp(s->serial_str, "0"))
  365 + features |= 1 << VIRTIO_BLK_F_IDENTIFY;
316 366  
317 367 return features;
318 368 }
... ... @@ -356,6 +406,7 @@ VirtIODevice *virtio_blk_init(DeviceState *dev)
356 406 int cylinders, heads, secs;
357 407 static int virtio_blk_id;
358 408 BlockDriverState *bs;
  409 + char *ps;
359 410  
360 411 s = (VirtIOBlock *)virtio_common_init("virtio-blk", VIRTIO_ID_BLOCK,
361 412 sizeof(struct virtio_blk_config),
... ... @@ -367,6 +418,10 @@ VirtIODevice *virtio_blk_init(DeviceState *dev)
367 418 s->vdev.reset = virtio_blk_reset;
368 419 s->bs = bs;
369 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 425 bs->private = dev;
371 426 bdrv_guess_geometry(s->bs, &cylinders, &heads, &secs);
372 427 bdrv_set_geometry_hint(s->bs, cylinders, heads, secs);
... ...
hw/virtio-blk.h
... ... @@ -30,6 +30,11 @@
30 30 #define VIRTIO_BLK_F_RO 5 /* Disk is read-only */
31 31 #define VIRTIO_BLK_F_BLK_SIZE 6 /* Block size of disk is available*/
32 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 39 struct virtio_blk_config
35 40 {
... ... @@ -39,6 +44,8 @@ struct virtio_blk_config
39 44 uint16_t cylinders;
40 45 uint8_t heads;
41 46 uint8_t sectors;
  47 + uint32_t _blk_size; /* structure pad, currently unused */
  48 + uint16_t identify[VIRTIO_BLK_ID_LEN];
42 49 } __attribute__((packed));
43 50  
44 51 /* These two define direction. */
... ...
sysemu.h
... ... @@ -154,6 +154,8 @@ typedef enum {
154 154 BLOCK_ERR_STOP_ANY
155 155 } BlockInterfaceErrorAction;
156 156  
  157 +#define BLOCK_SERIAL_STRLEN 20
  158 +
157 159 typedef struct DriveInfo {
158 160 BlockDriverState *bdrv;
159 161 const char *devaddr;
... ... @@ -163,7 +165,7 @@ typedef struct DriveInfo {
163 165 int used;
164 166 int drive_opt_idx;
165 167 BlockInterfaceErrorAction onerror;
166   - char serial[21];
  168 + char serial[BLOCK_SERIAL_STRLEN + 1];
167 169 } DriveInfo;
168 170  
169 171 #define MAX_IDE_DEVS 2
... ...