The virtio spec has had a de facto command for drivers to read the
serial number off a virtual block device. QEMU introduced this feature
years ago. Last November, the virtio governing group voted in favor of
adopting it officially into v1.2 (the next virtio spec) [1].

The below diff adds the basics of handling the request returning an
empty serial number. (Serial numbers are limited to 20 bytes.) This
stops vmd from complaining about "unsupported command 0x8" when guests
send this command type.

secdata_desc{,idx} variables are renamed to just data_desc{,idx} to
semantically match the change since they're used for more than sector
data.

This is primarily part of my work to clean up and bring vmd's virtio
implementation more up to date and to align to our own
v{io,ioblk,ioscsi,etc.}(4) current capabilities. (vioblk(4) doesn't
support this yet, but Linux guests use it frequently.)

OK?

-dv

[1] https://www.oasis-open.org/committees/ballot.php?id=3536


Index: virtio.c
===================================================================
RCS file: /cvs/src/usr.sbin/vmd/virtio.c,v
retrieving revision 1.89
diff -u -p -r1.89 virtio.c
--- virtio.c    16 Jun 2021 16:55:02 -0000      1.89
+++ virtio.c    17 Jun 2021 00:10:15 -0000
@@ -460,15 +460,16 @@ vioblk_notifyq(struct vioblk_dev *dev)
 {
        uint64_t q_gpa;
        uint32_t vr_sz;
-       uint16_t idx, cmd_desc_idx, secdata_desc_idx, ds_desc_idx;
+       uint16_t idx, cmd_desc_idx, data_desc_idx, ds_desc_idx;
        uint8_t ds;
        int cnt, ret;
        off_t secbias;
        char *vr;
-       struct vring_desc *desc, *cmd_desc, *secdata_desc, *ds_desc;
+       struct vring_desc *desc, *cmd_desc, *data_desc, *ds_desc;
        struct vring_avail *avail;
        struct vring_used *used;
        struct virtio_blk_req_hdr cmd;
+       char blkid[VIRTIO_BLK_ID_BYTES];

        ret = 0;

@@ -526,10 +527,10 @@ vioblk_notifyq(struct vioblk_dev *dev)
                switch (cmd.type) {
                case VIRTIO_BLK_T_IN:
                        /* first descriptor */
-                       secdata_desc_idx = cmd_desc->next & VIOBLK_QUEUE_MASK;
-                       secdata_desc = &desc[secdata_desc_idx];
+                       data_desc_idx = cmd_desc->next & VIOBLK_QUEUE_MASK;
+                       data_desc = &desc[data_desc_idx];

-                       if ((secdata_desc->flags & VRING_DESC_F_NEXT) == 0) {
+                       if ((data_desc->flags & VRING_DESC_F_NEXT) == 0) {
                                log_warnx("unchained vioblk data descriptor "
                                    "received (idx %d)", cmd_desc_idx);
                                goto out;
@@ -542,7 +543,7 @@ vioblk_notifyq(struct vioblk_dev *dev)
                                const uint8_t *secdata;

                                info = vioblk_start_read(dev,
-                                   cmd.sector + secbias, secdata_desc->len);
+                                   cmd.sector + secbias, data_desc->len);

                                /* read the data, use current data descriptor */
                                secdata = vioblk_finish_read(info);
@@ -553,11 +554,11 @@ vioblk_notifyq(struct vioblk_dev *dev)
                                        goto out;
                                }

-                               if (write_mem(secdata_desc->addr, secdata,
-                                       secdata_desc->len)) {
+                               if (write_mem(data_desc->addr, secdata,
+                                       data_desc->len)) {
                                        log_warnx("can't write sector "
                                            "data to gpa @ 0x%llx",
-                                           secdata_desc->addr);
+                                           data_desc->addr);
                                        dump_descriptor_chain(desc,
                                            cmd_desc_idx);
                                        vioblk_free_info(info);
@@ -566,11 +567,11 @@ vioblk_notifyq(struct vioblk_dev *dev)

                                vioblk_free_info(info);

-                               secbias += (secdata_desc->len /
+                               secbias += (data_desc->len /
                                    VIRTIO_BLK_SECTOR_SIZE);
-                               secdata_desc_idx = secdata_desc->next &
+                               data_desc_idx = data_desc->next &
                                    VIOBLK_QUEUE_MASK;
-                               secdata_desc = &desc[secdata_desc_idx];
+                               data_desc = &desc[data_desc_idx];

                                /* Guard against infinite chains */
                                if (++cnt >= VIOBLK_QUEUE_SIZE) {
@@ -578,27 +579,27 @@ vioblk_notifyq(struct vioblk_dev *dev)
                                            "invalid", __func__);
                                        goto out;
                                }
-                       } while (secdata_desc->flags & VRING_DESC_F_NEXT);
+                       } while (data_desc->flags & VRING_DESC_F_NEXT);

-                       ds_desc_idx = secdata_desc_idx;
-                       ds_desc = secdata_desc;
+                       ds_desc_idx = data_desc_idx;
+                       ds_desc = data_desc;

                        ds = VIRTIO_BLK_S_OK;
                        break;
                case VIRTIO_BLK_T_OUT:
-                       secdata_desc_idx = cmd_desc->next & VIOBLK_QUEUE_MASK;
-                       secdata_desc = &desc[secdata_desc_idx];
+                       data_desc_idx = cmd_desc->next & VIOBLK_QUEUE_MASK;
+                       data_desc = &desc[data_desc_idx];

-                       if ((secdata_desc->flags & VRING_DESC_F_NEXT) == 0) {
+                       if ((data_desc->flags & VRING_DESC_F_NEXT) == 0) {
                                log_warnx("wr vioblk: unchained vioblk data "
                                    "descriptor received (idx %d)",
                                    cmd_desc_idx);
                                goto out;
                        }

-                       if (secdata_desc->len > dev->max_xfer) {
+                       if (data_desc->len > dev->max_xfer) {
                                log_warnx("%s: invalid read size %d requested",
-                                   __func__, secdata_desc->len);
+                                   __func__, data_desc->len);
                                goto out;
                        }

@@ -609,12 +610,12 @@ vioblk_notifyq(struct vioblk_dev *dev)

                                info = vioblk_start_write(dev,
                                    cmd.sector + secbias,
-                                   secdata_desc->addr, secdata_desc->len);
+                                   data_desc->addr, data_desc->len);

                                if (info == NULL) {
                                        log_warnx("wr vioblk: can't read "
                                            "sector data @ 0x%llx",
-                                           secdata_desc->addr);
+                                           data_desc->addr);
                                        dump_descriptor_chain(desc,
                                            cmd_desc_idx);
                                        goto out;
@@ -629,12 +630,12 @@ vioblk_notifyq(struct vioblk_dev *dev)

                                vioblk_free_info(info);

-                               secbias += secdata_desc->len /
+                               secbias += data_desc->len /
                                    VIRTIO_BLK_SECTOR_SIZE;

-                               secdata_desc_idx = secdata_desc->next &
+                               data_desc_idx = data_desc->next &
                                    VIOBLK_QUEUE_MASK;
-                               secdata_desc = &desc[secdata_desc_idx];
+                               data_desc = &desc[data_desc_idx];

                                /* Guard against infinite chains */
                                if (++cnt >= VIOBLK_QUEUE_SIZE) {
@@ -642,10 +643,10 @@ vioblk_notifyq(struct vioblk_dev *dev)
                                            "invalid", __func__);
                                        goto out;
                                }
-                       } while (secdata_desc->flags & VRING_DESC_F_NEXT);
+                       } while (data_desc->flags & VRING_DESC_F_NEXT);

-                       ds_desc_idx = secdata_desc_idx;
-                       ds_desc = secdata_desc;
+                       ds_desc_idx = data_desc_idx;
+                       ds_desc = data_desc;

                        ds = VIRTIO_BLK_S_OK;
                        break;
@@ -654,6 +655,29 @@ vioblk_notifyq(struct vioblk_dev *dev)
                        ds_desc_idx = cmd_desc->next & VIOBLK_QUEUE_MASK;
                        ds_desc = &desc[ds_desc_idx];

+                       ds = VIRTIO_BLK_S_OK;
+                       break;
+               case VIRTIO_BLK_T_GET_ID:
+                       data_desc_idx = cmd_desc->next & VIOBLK_QUEUE_MASK;
+                       data_desc = &desc[data_desc_idx];
+
+                       if ((data_desc->flags & VRING_DESC_F_NEXT) == 0) {
+                               log_warnx("vioblk: unchained vioblk data "
+                                   "descriptor received (idx %d)",
+                                   cmd_desc_idx);
+                               goto out;
+                       }
+
+                       /* We don't provide a block id (serial number) yet. */
+                       memset(blkid, 0, sizeof(blkid));
+                       if (write_mem(data_desc->addr, blkid, sizeof(blkid))) {
+                               log_warnx("%s: can't write device id data @ "
+                                   "0x%llx", __func__, data_desc->addr);
+                               goto out;
+                       }
+
+                       ds_desc_idx = data_desc->next & VIOBLK_QUEUE_MASK;
+                       ds_desc = &desc[ds_desc_idx];
                        ds = VIRTIO_BLK_S_OK;
                        break;
                default:

Reply via email to