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