Commit bf011293faaa7f87e4de83185931e7411b794128
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>
Showing
3 changed files
with
65 additions
and
1 deletions
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 |