virtio-blk: add feature VIRTIO_BLK_F_SIZE_MAX and VIRTIO_BLK_F_SEG_MAX

according to virtio spec, add feature VIRTIO_BLK_F_SIZE_MAX
and VIRTIO_BLK_F_SEG_MAX parse to virtio blk driver.

Signed-off-by: Andy Pei <andy.pei@intel.com>
Signed-off-by: Ding Limin <dinglimin@cmss.chinamobile.com>
Reviewed-by: Gerd Hoffmann <kraxel@redhat.com>
diff --git a/src/block.h b/src/block.h
index c1b8d73..3af2d71 100644
--- a/src/block.h
+++ b/src/block.h
@@ -57,6 +57,8 @@
     u8 translation;     // type of translation
     u16 blksize;        // block size
     struct chs_s pchs;  // Physical CHS
+    u32 max_segment_size; //max_segment_size
+    u32 max_segments;   //max_segments
 };
 
 #define DISK_SECTOR_SIZE  512
diff --git a/src/hw/virtio-blk.c b/src/hw/virtio-blk.c
index 3b19896..2653dad 100644
--- a/src/hw/virtio-blk.c
+++ b/src/hw/virtio-blk.c
@@ -121,12 +121,16 @@
         u64 version1 = 1ull << VIRTIO_F_VERSION_1;
         u64 iommu_platform = 1ull << VIRTIO_F_IOMMU_PLATFORM;
         u64 blk_size = 1ull << VIRTIO_BLK_F_BLK_SIZE;
+        u64 max_segments = 1ull << VIRTIO_BLK_F_SEG_MAX;
+        u64 max_segment_size = 1ull << VIRTIO_BLK_F_SIZE_MAX;
+
         if (!(features & version1)) {
             dprintf(1, "modern device without virtio_1 feature bit: %pP\n", pci);
             goto fail;
         }
 
-        features = features & (version1 | iommu_platform | blk_size);
+        features = features & (version1 | iommu_platform | blk_size
+                        | max_segments | max_segment_size);
         vp_set_features(vp, features);
         status |= VIRTIO_CONFIG_S_FEATURES_OK;
         vp_set_status(vp, status);
@@ -135,6 +139,14 @@
             goto fail;
         }
 
+        if (features & max_segment_size)
+            vdrive->drive.max_segment_size =
+                vp_read(&vp->device, struct virtio_blk_config, size_max);
+
+        if (features & max_segments)
+            vdrive->drive.max_segments =
+                vp_read(&vp->device, struct virtio_blk_config, seg_max);
+
         vdrive->drive.sectors =
             vp_read(&vp->device, struct virtio_blk_config, capacity);
         if (features & blk_size) {
@@ -148,8 +160,10 @@
                     pci, vdrive->drive.blksize);
             goto fail;
         }
-        dprintf(3, "virtio-blk %pP blksize=%d sectors=%u\n",
-                pci, vdrive->drive.blksize, (u32)vdrive->drive.sectors);
+        dprintf(3, "virtio-blk %pP blksize=%d sectors=%u size_max=%u "
+                "seg_max=%u.\n", pci, vdrive->drive.blksize,
+                (u32)vdrive->drive.sectors, vdrive->drive.max_segment_size,
+                vdrive->drive.max_segments);
 
         vdrive->drive.pchs.cylinder =
             vp_read(&vp->device, struct virtio_blk_config, cylinders);
@@ -165,9 +179,17 @@
         vdrive->drive.blksize = (f & (1 << VIRTIO_BLK_F_BLK_SIZE)) ?
             cfg.blk_size : DISK_SECTOR_SIZE;
 
+        if (f & (1 << VIRTIO_BLK_F_SIZE_MAX))
+            vdrive->drive.max_segment_size = cfg.size_max;
+
+        if (f & (1 << VIRTIO_BLK_F_SEG_MAX))
+            vdrive->drive.max_segments = cfg.seg_max;
+
         vdrive->drive.sectors = cfg.capacity;
-        dprintf(3, "virtio-blk %pP blksize=%d sectors=%u\n",
-                pci, vdrive->drive.blksize, (u32)vdrive->drive.sectors);
+        dprintf(3, "virtio-blk %pP blksize=%d sectors=%u size_max=%u "
+                "seg_max=%u.\n", pci, vdrive->drive.blksize,
+                (u32)vdrive->drive.sectors, vdrive->drive.max_segment_size,
+                vdrive->drive.max_segments);
 
         if (vdrive->drive.blksize != DISK_SECTOR_SIZE) {
             dprintf(1, "virtio-blk %pP block size %d is unsupported\n",
@@ -218,8 +240,11 @@
     u64 features = vp_get_features(vp);
     u64 version1 = 1ull << VIRTIO_F_VERSION_1;
     u64 blk_size = 1ull << VIRTIO_BLK_F_BLK_SIZE;
+    u64 max_segments = 1ull << VIRTIO_BLK_F_SEG_MAX;
+    u64 max_segment_size = 1ull << VIRTIO_BLK_F_SIZE_MAX;
 
-    features = features & (version1 | blk_size);
+    features = features & (version1 | blk_size
+            | max_segments | max_segment_size);
     vp_set_features(vp, features);
     status |= VIRTIO_CONFIG_S_FEATURES_OK;
     vp_set_status(vp, status);
@@ -228,6 +253,14 @@
         goto fail;
     }
 
+    if (features & max_segment_size)
+        vdrive->drive.max_segment_size =
+            vp_read(&vp->device, struct virtio_blk_config, size_max);
+
+    if (features & max_segments)
+        vdrive->drive.max_segments =
+            vp_read(&vp->device, struct virtio_blk_config, seg_max);
+
     vdrive->drive.sectors =
         vp_read(&vp->device, struct virtio_blk_config, capacity);
     if (features & blk_size) {
@@ -241,8 +274,10 @@
                 mmio, vdrive->drive.blksize);
         goto fail;
     }
-    dprintf(1, "virtio-blk-mmio %p blksize=%d sectors=%u\n",
-            mmio, vdrive->drive.blksize, (u32)vdrive->drive.sectors);
+    dprintf(1, "virtio-blk-mmio %p blksize=%d sectors=%u size_max=%u "
+            "seg_max=%u.\n", mmio, vdrive->drive.blksize,
+            (u32)vdrive->drive.sectors, vdrive->drive.max_segment_size,
+            vdrive->drive.max_segments);
 
     vdrive->drive.pchs.cylinder =
         vp_read(&vp->device, struct virtio_blk_config, cylinders);
diff --git a/src/hw/virtio-blk.h b/src/hw/virtio-blk.h
index d20461a..0294291 100644
--- a/src/hw/virtio-blk.h
+++ b/src/hw/virtio-blk.h
@@ -16,6 +16,9 @@
     u32 opt_io_size;
 } __attribute__((packed));
 
+/* Feature bits */
+#define VIRTIO_BLK_F_SIZE_MAX 1  /* Maximum size of any single segment */
+#define VIRTIO_BLK_F_SEG_MAX 2   /* Maximum number of segments in a request */
 #define VIRTIO_BLK_F_BLK_SIZE 6
 
 /* These two define direction. */