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 | 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 | ... | ... |